(1)Spring回顾
①Spring是什么?
Spring是一个轻量级DI/IOC与AOP的容器框架
- DI(依赖注入)
- IOC(控制反转)
- AOP(面向切面)
面试题:BeanFactory与ApplicationContext的区别?
答:ApplicationContext是BeanFactory的子类,它拥有更加强大的一些方法(邮件,国际化,…),BeanFactory创建的Bean默认是懒加载,ApplicationContext是迫切加载!!!
②导包(Spring)
- ApplicationContext.xml配置文件中配置
配置Spring需要的包
①Spring的核心包 spring-core
②Context包 spring-context
③aop的包 spring-aop
④切面的一个包(织入) aspectjweaver
⑤Spring的测试包 spring-test
⑥junit的测试支持 junit
<!--Spring的核心包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
<!--Context包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
<!--aop的包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
<!--切面的一个包(织入)-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.8</version>
</dependency>
<!-- Spring的测试包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.2.5.RELEASE</version>
<!--scope:范围,只能在test包中使用-->
<scope>test</scope>
</dependency>
<!--junit的测试支持-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
③引入一些插件与资源
- 需要读到java中的xml文件(默认不会编译)
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/test/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
(2)构造器注入
通过constructor-arg标签注入
- index:索引
- name:属性名
- type:属性类型
- 默认不写:按照顺序注入
- value:普通值
- ref:引用类型(外部引用)
例:
①index:索引
<bean id="myBean" class="com.luo._02_constructor.MyBean">
<constructor-arg index="0" value="小王八"/>
<constructor-arg index="1" value="18"/>
</bean>
②name:属性名
<bean id="myBean" class="com.luo._02_constructor.MyBean">
<constructor-arg name="name" value="小王八羔子"/>
<constructor-arg name="age" value="8"/>
</bean>
③type:属性类型
<bean id="myBean" class="com.luo._02_constructor.MyBean">
<constructor-arg type="java.lang.String" value="老乌龟"/>
<constructor-arg type="java.lang.Integer" value="88"/>
</bean>
④默认不写:按照顺序注入
<bean id="myBean" class="com.luo._02_constructor.MyBean">
<constructor-arg value="老乌龟"/>
<constructor-arg value="88"/>
</bean>
引用类型:外部与内部引用两种方式
⑤ref:外部引用
<bean id="youBean" class="com.luo._02_constructor.YouBean"></bean>
<bean id="myBean" class="com.luo._02_constructor.MyBean">
<constructor-arg value="aaa"/>
<constructor-arg value="66"/>
<!--外部引入-->
<!--<constructor-arg ref="youBean"/>-->
<constructor-arg>
<!--内部引入-->
<bean class="com.luo._02_constructor.YouBean"></bean>
</constructor-arg>
</bean>
⑥内部引用
<bean id="myBean" class="com.luo._02_constructor.MyBean">
<constructor-arg>
<!--内部引入-->
<bean class="com.luo._02_constructor.YouBean"></bean>
</constructor-arg>
</bean>
(3)属性注入
①普通属性注入
<bean id="myBean" class="com.luo._03_di.MyBean">
<property name="id" value="2"/>
<property name="name" value="古二娃"/>
<property name="sex" value="true"/>
<property name="salary" value="8000"/>
</bean>
②List/Set/Map注入
普通属性注入
List<String> list;
Set<String> set;
Map<Integer,String> map;
<bean id="myBean" class="com.luo._03_di.MyBean">
<property name="list">
<!--有序可重复-->
<list>
<value>孤儿</value>
<value>秀儿</value>
<value>低能儿</value>
<value>低能儿</value>
</list>
</property>
<property name="set">
<!--无需不可重复-->
<set>
<value>悟空</value>
<value>八戒</value>
<value>老沙</value>
<value>老沙</value>
</set>
</property>
<property name="map">
<map>
<entry key="1" value="aaa"/>
<entry key="2" value="bbb"/>
<entry key="3" value="ccc"/>
</map>
</property>
</bean>
引用类型注入
List<OtherBean> otherBeanList;
Set<OtherBean> otherBeanSet;
Map<Integer,OtherBean> otherBeanMap;
<bean id="myBean" class="com.luo._03_di.MyBean">
<!--List<OtherBean> otherBeanList;-->
<property name="otherBeanList">
<list>
<!--内部引入-->
<bean class="com.luo._03_di.OtherBean"/>
<bean class="com.luo._03_di.OtherBean"/>
<!--外部引入-->
<ref bean="otherBean"/>
<ref bean="otherBean"/>
</list>
</property>
<!--Set<OtherBean> otherBeanSet;-->
<property name="otherBeanSet">
<set>
<!--内部引入-->
<bean class="com.luo._03_di.OtherBean"/>
<bean class="com.luo._03_di.OtherBean"/>
<!--外部引入-->
<ref bean="otherBean"/>
<ref bean="otherBean"/>
</set>
</property>
<!--Map<Integer,OtherBean> otherBeanMap;-->
<property name="otherBeanMap">
<map>
<entry key="1" value-ref="otherBean"/>
<entry key="2" value-ref="otherBean"/>
<entry key="3" value-ref="otherBean"/>
</map>
</property>
</bean>
③数组注入
private String[] arrays;
<bean id="myBean" class="com.luo._03_di.MyBean">
<!--String[] arrays;-->
<!--<property name="arrays">
<array>
<value>一</value>
<value>二</value>
<value>三</value>
</array>
</property>-->
<!--简写格式-->
<property name="arrays" value="四,五,六"/>
</bean>
④Properties注入
private Properties props1;
private Properties props2;
<bean id="myBean" class="com.luo._03_di.MyBean">
<!--Properties props1;-->
<property name="props1">
<props>
<prop key="kkk">KKKKK中国</prop>
<prop key="aaa">AAAAA</prop>
<prop key="bbb">BBBBB</prop>
</props>
</property>
<!--简写格式(不支持中文)-->
<property name="props2">
<value>
<!--可以空格和=号分隔-->
<!-- kkk KKKKK中国
aaa AAAAA
bbb BBBBB-->
kkk=KKKKK中国
aaa=AAAAA
bbb=BBBBB
</value>
</property>
</bean>
(4)XML的自动注入(了解即可,不用管)
- 自动注入有两种方式 (通过类型与通过名称)
- 设置全局的自动注入 <beans … default-autowire=“byType/byName”>
- 单独为某一个bean配置自动注入 <bean … autowire=“byType/byName”>
(5)全注解(重要)
①全注解配置及使用
xml配置context
扫描相应的包
<context:component-scan base-package="com.luo._04_anno"/>
具体配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
">
<!--扫描包-->
<context:component-scan base-package="com.luo._04_anno"/>
</beans>
在相应的类上加注解
- @Controller:控制层
- @Service:业务层
- @Repository:持久层
- @Component:组件(一个bean不知道在哪一层用这个)
- @Autowired:注入功能
②如果出现多个bean类型一样怎么办?
- 注解的bean有默认名称(类名【首字母小写】) 如 userDaoImpl
- 先通过类型注入,再通过名称注入
- 修改bean的名称 Component/Service/Repository/Controller(“名称”)
- 在注入bean的时候加上一个限定注解 (通过注解确定名称)
@Autowired
@Qualifier("userJPADaoImpl")
//@Resource(name = "userJDBCDao")
private IUserDao userDao;
(6)代理模式(了解即可)
概念图:
- 代理模式分为静态代理和动态代理
- 静态代理和装饰者有些相似,但是没什么用
- Spring使用的是动态代理,有两种方式,由Spring自行选择
①JDK方式(有接口的时候用)
②没有接口的是CGLIB
动态代理
格式:
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
new Class[] { Foo.class },
handler);
- newProxyInstance:创建代理对象
- 参数1:ClassLoader loader :类加载器(随便给它一个)
- 参数2:Class<?>[] interfaces:接口(为什么这里是一个数组)
- 参数3:InvocationHandler:处理器,为了增强功能(自己实现)
//准备一个真实主题颜色对象
IUserService userService = new UserServiceImpl();
IUserService proxy = (IUserService)Proxy.newProxyInstance(userService.getClass().getClassLoader(),
userService.getClass().getInterfaces(),
new InvocationHandler() {
//实现的代码
/*
* Object proxy:代理对象(不用它)
* Method method:执行方法
* Object[] args:方法参数
* */
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
TxManager txManager = new TxManager();
Object result = null;
try {
txManager.begin();
//在这里面完成功能增强
//通过反射执行相应的方法
result = method.invoke(userService, args);
txManager.commit();
} catch (Exception e) {
txManager.rollback();
e.printStackTrace();
} finally {
txManager.close();
}
return result;
}
}
);
proxy.delete();
(7)Spring的AOP
XML版本
aop配置
三要素:何时,何地,做什么
①引入aop的头
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
">
②配置真实主题角色
<bean id="userService" class="com.luo._07_aopxml.service.impl.UserServiceImpl"></bean>
③配置事务管理对象,用于增强
<bean id="txManager" class="com.luo._07_aopxml.TxManager"></bean>
④配置三要素(何时,何地,做什么)
何地:该包的I开头Service结尾的接口的所有方法切面
<aop:pointcut id="pointcut" expression="execution(* com.luo._07_aopxml.service.I*Service.*(..))"/>
何时:
- aop:before 前置通知
- aop:after-returning 后置通知
- aop:after-throwing 异常通知
- aop:after 最终通知
- aop:around 环绕通知(可取代以上所有)
- aop:aspect->切面(切点与增强)
- ref=“txManager”:引入增强的类
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.luo._07_aopxml.service.I*Service.*(..))"/>
<aop:aspect ref="txManager">
<!--前置通知-->
<!--<aop:before method="begin" pointcut-ref="pointcut"/>-->
<!--后置通知-->
<!--<aop:after-returning method="commit" pointcut-ref="pointcut"/>-->
<!--异常通知-->
<!--<aop:after-throwing method="rollback" pointcut-ref="pointcut" throwing="e"/>-->
<!--后置通知-->
<!--<aop:after method="close" pointcut-ref="pointcut"/>-->
<!--环绕通知 可以取代上面所有通知-->
<aop:around method="around" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
⑤若使用环绕通知
若使用环绕测试,如果有环绕通知,其它通知就不需要了,并且
需要在事务对象中定义around(ProceedingJoinPoint joinPoint)方法
- ProceedingJoinPoint joinPoint Spring会为你传一个连接点对象
- joinPoint.proceed();//执行方法
public class TxManager {
public void begin(){
System.out.println("开启事务...");
}
public void commit(){
System.out.println("提交事务...");
}
public void rollback(Throwable e){
System.out.println("回滚事务...原因是:"+e.getMessage());
}
public void close(){
System.out.println("关闭事务...");
}
//连接点 Spring会为你传一个连接点对象
public void around(ProceedingJoinPoint joinPoint){
//System.out.println(joinPoint.getArgs());//方法参数
//System.out.println(joinPoint.getSignature());//方法签名(包含方法的所有信息)
//System.out.println(joinPoint.getTarget());//真实对象
//System.out.println(joinPoint.getThis());//代理对象
try {
begin();
joinPoint.proceed();//执行方法
commit();
} catch (Throwable e) {
rollback(e);
e.printStackTrace();
} finally {
close();
}
}
}
⑥xml全部代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
">
<!--配置真实主题角色-->
<bean id="userService" class="com.luo._07_aopxml.service.impl.UserServiceImpl"></bean>
<!--配置事务管理对象,用于增强-->
<bean id="txManager" class="com.luo._07_aopxml.TxManager"></bean>
<!--
aop配置
三要素:何时,何地,做什么
切点id:随便取
表达式 expression(何地):execution(* com.luo._07_aopxml.service.I*Service.*(..))
定义到I*Service的所有方法
aop:aspect->切面(切点与增强)
ref="txManager":引入增强的类
aop:before:前置通知
aop:after-returning:后置通知
aop:after-throwing:异常通知(异常抛出去才能使用)与Throwable e的e相同
aop:after:最终通知
try {
aop:before:前置通知
//通过反射执行方法
result = method.invoke(userService, args);
aop:after-returning:后置通知
} catch (Exception e) {
aop:after-throwing
e.printStackTrace();
} finally {
aop:after:最终通知
}
aop:around:环绕通知(可以取代上面的所有通知)
-->
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.luo._07_aopxml.service.I*Service.*(..))"/>
<aop:aspect ref="txManager">
<!--<!–前置通知–>
<aop:before method="begin" pointcut-ref="pointcut"/>
<!–后置通知–>
<aop:after-returning method="commit" pointcut-ref="pointcut"/>
<!–异常通知–>
<aop:after-throwing method="rollback" pointcut-ref="pointcut" throwing="e"/>
<!–后置通知–>
<aop:after method="close" pointcut-ref="pointcut"/>-->
<!--环绕通知 可以取代上面所有通知-->
<aop:around method="around" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
</beans>
⑦测试方式
- 查看一下这个对象是否已经被代理
- 声明必需是接口
- 测试一下有异常与没有异常的区别
全注解版本
需要在相应的bean上加注解控制层/业务层/持久层/普通组件…
- ①引入aop和context的头
- ②开启扫描包
- ③开启支持aop注解
- ④其他配置都在T下Manager(事物类中)
xml配置①②③
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
">
<!--开启扫描包-->
<context:component-scan base-package="com.luo._08_aopanno"/>
<!--支持aop注解-->
<aop:aspectj-autoproxy/>
</beans>
TxManager类配置④
- 注意:切点的名字是方法名()
@Component
@Aspect //<aop:aspect ref="txManager">
public class TxManager {
/*
* 配置一个切点(随便定义一个方法,方法名随意取)
* <aop:pointcut id="pointcut" expression="execution(* com.luo._07_aopxml.service.I*Service.*(..))"/>
* */
@Pointcut("execution(* com.luo._08_aopanno.service.I*Service.*(..))")
public void pointcut(){}
//前置通知 <aop:before method="begin" pointcut-ref="pointcut"/>
//@Before("pointcut()")//注意用的是方法名加() pointcut()
public void begin(){
System.out.println("开启事务...");
}
//@AfterReturning("pointcut()")
public void commit(){
System.out.println("提交事务...");
}
//@AfterThrowing(value = "pointcut()",throwing = "e")
public void rollback(Throwable e){
System.out.println("回滚事务...原因是:"+e.getMessage());
}
//@After("pointcut()")
public void close(){
System.out.println("关闭事务...");
}
@Around("pointcut()")//环绕通知
public void around(ProceedingJoinPoint joinPoint){
try {
begin();
joinPoint.proceed();
commit();
} catch (Throwable e) {
rollback(e);
e.printStackTrace();
} finally {
close();
}
}
}