回顾
1,组件扫描过滤器
-
xml版
<!--组件扫描--> <context:component-scan base-package="com.itheima"> <!--排除service注解--> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/> </context:component-scan>
-
注解版
@ComponentScan( value = "com.itheima", excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Service.class) )
2,AOP
概述: 面向切面编程。是一种思想。而spring对AOP思想进行了实现。
术语:
- 连接点
- 切入点
- 通知
- 切面 --> 切入点和通知的关系
- 织入
切入点表达式:
excution(返回值类型 包名.类名.方法名(参数类型))
通知类型:
- 前置通知
- 后置通知
- 返回时通知
- 异常通知
- 环绕通知
<aop:config>
<aop:pointcut id="pt" expression="execution(* *..*(..))"/>
<aop:aspect ref="myAdvice">
<aop:after-returning method="afterReturing" pointcut-ref="pt"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="pt"/>
<aop:after method="after" pointcut-ref="pt"/>
<aop:before method="before" pointcut-ref="pt"/>
<!--<aop:around method="around" pointcut-ref="pt"/>-->
</aop:aspect>
</aop:config>
今日内容
- 注解版的AOP使用
- 案例
- AOP底层原理
- 事务管理
- 编程式事务
- 声明式事务(掌握)
1,AOP实现(注解+xml)
2,开启aop注解驱动
-
xml方式
<aop:aspectj-autoproxy/>
-
注解方式
在配置类上加下面的注解
@EnableAspectJAutoProxy
3,AOP底层原理(了解)
3.1 装饰者模式
3.2 jdk的动态代理
//1,如何获取动态代理对象
/*
动态代理: 在运行过程中动态的增强功能
代理类: 在内存中生成
代理类是接口的子实现类
参数:
ClassLoader loader : 获取当前类的字节码对象,然后获取类加载器
为什么需要传递类加载器呢?用来加载代理类的
Class<?>[] interfaces : 接口的字节码对象数组
指定代理类的父接口
InvocationHandler h : 方法调用的处理程序
*/
UserService userService = (UserService) Proxy.newProxyInstance(
Demo.class.getClassLoader(),
new Class[]{UserService.class},
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我被执行了");
return null;
}
}
);
//通过代理对象调用方法
userService.save();
注意:
- 代理类和目标类的关系是兄弟关系
3.3 CGLIB代理
核心对象
Enhancer
注意:
1.代理类和目标类是子父关系
2.代理类动态的在内存中生成
3.目标类不能使用final修饰
4.要增强的方法不能使用final修饰
public static UserService createUserServiceCglibProxy(Class clazz) throws IllegalAccessException, InstantiationException {
//创建Enhancer对象(可以理解为内存中动态创建了一个类的字节码)
Enhancer enhancer = new Enhancer();
//设置Enhancer对象的父类是指定类型UserServerImpl
enhancer.setSuperclass(clazz);
//设置回调方法
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
//通过调用父类的方法实现对原始方法的调用
Object ret = methodProxy.invokeSuper(o, args);
//后置增强内容,与JDKProxy区别:JDKProxy仅对接口方法做增强,cglib对所有方法做增强,包括Object类中的方法
if(method.getName().equals("save")) {
System.out.println("刮大白3");
System.out.println("贴墙纸3");
}
return ret;
}
});
//使用Enhancer对象创建对应的对象
UserService userService = (UserService) enhancer.create();
System.out.println(userService);
if(true) {
while(true) {}
}
return userService;
}
AOP的原理:
默认使用的是jdk的动态代理。
spring会根据目标类有没有实现接口判断,如果实现了,使用jdk的动态代理,如果没有实现,使用CGLIB代理。
当然我们也可以通过设置,使目标类无论是否实现接口,都使用CGLIB代理。
<!---注解方式的aop-->
<aop:aspectj-autoproxy proxy-target-class="true"/>
<!--xml方式的AOP-->
<aop:config proxy-target-class="true">
</aop:config>
//纯注解
@EnableAspectJAutoProxy(proxyTargetClass = true)
面试题:
聊聊AOP的原理。
小扩展:设计模式有23种接触到的有以下几种:
-
单例模式
-
工厂模式
- 简单工厂模式
- 工厂方法模式
- 抽象工厂模式
-
代理
-
静态代理 : 屏蔽对象
public class UserServiceImplDecorator implements UserService { private UserService userService = new UserServiceImpl(); public void save() { //原始调用 userService.save(); //增强功能(后置) System.out.println("刮大白"); } }
-
动态代理
-
-
构建者模式
-
模板方法模式
-
装饰者模式 : 对业务对象进行增强
public class UserServiceImplDecorator implements UserService { private UserService userService; public UserServiceImplDecorator(UserService userService){ this.userService = userService; } public void save() { //原始调用 userService.save(); //增强功能(后置) System.out.println("刮大白"); } } 要求: 1.装饰者类和业务类实现相同的接口 2.在装饰者类中提供一个业务接口的成员变量 3.提供一个构造方法给成员变量进行赋值。
4,事务控制
概述: 逻辑上的一组操作,这组操作要么全部成功,要么全部失败。
ACID(酸性):一致性,原子性,隔离性,持久性
隔离级别:
- read uncommitted
- read committed (oracle)
- Repeatable (mysql)
- Serializable
4.1 编程式事务控制(了解)
- 事务相关对象 (知道)
- 平台事务管理器 PlatformTransactionManager --> DataSourceTransactionManager
- 事务定义对象 TransactionDefinition
- 事务状态对象 TransactionStatus
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
private DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public void transfer(String outName, String inName, Double money) {
//开启事务
PlatformTransactionManager ptm = new DataSourceTransactionManager(dataSource);
//事务定义
TransactionDefinition td = new DefaultTransactionDefinition();
//事务状态
TransactionStatus ts = ptm.getTransaction(td);
try {
accountDao.inMoney(outName, money);
int i = 1 / 0;
accountDao.outMoney(inName, money);
//提交事务
ptm.commit(ts);
} catch (Exception e) {
ptm.rollback(ts);
throw new RuntimeException(e);
}
}
}
AOP改进
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
public void transfer(String outName, String inName, Double money) {
accountDao.inMoney(outName,money);
int i = 1/0;
accountDao.outMoney(inName,money);
}
}
通知类:
public class TxAdvice {
private DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public Object transactionManager(ProceedingJoinPoint pjp) {
//开启事务
PlatformTransactionManager ptm = new DataSourceTransactionManager(dataSource);
//事务定义
TransactionDefinition td = new DefaultTransactionDefinition();
//事务状态
TransactionStatus ts = ptm.getTransaction(td);
Object ret = null;
try {
//执行目标方法
ret = pjp.proceed(pjp.getArgs());
//提交事务
ptm.commit(ts);
} catch (Throwable e) {
ptm.rollback(ts);
throw new RuntimeException(e);
}
return ret;
}
}
配置:
<bean id="txAdvice" class="com.itheima.aop.TxAdvice">
<property name="dataSource" ref="dataSource"/>
</bean>
<aop:config>
<aop:pointcut id="pt" expression="execution(* *..transfer(..))"/>
<aop:aspect ref="txAdvice">
<aop:around method="transactionManager" pointcut-ref="pt"/>
</aop:aspect>
</aop:config>
4.2 声明式事务控制(掌握)
4.2.1 基于xml的
只需要进行配置即可
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--定义事务管理的通知类-->
<tx:advice id="txAdvice" transaction-manager="txManager">
<!--定义控制的事务-->
<tx:attributes>
<tx:method name="*" read-only="false"/>
<tx:method name="find*" read-only="true"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="pt" expression="execution(* com.itheima.service.*Service.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>
</aop:config>
说明:spring对aop思想进行了实现,aspectj也对aop进行了实现,spring中的aop不好用,spring将aspectj整合进来了。
advisor和aspect区别:
- advisor是spring aop原生的配置
- 要求通知类必须实现相对应的接口。比如前置通知 MethodBeforeAdvice
- aspect是spring整合aspectj提供声明切面的标签
事务传播行为(理解)
概述:一个方法调用另一个方法,对事务的态度。
4.2.2 基于注解的
-
配置(开启声明式事务控制注解支持)
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <tx:annotation-driven transaction-manager="txManager"/>
-
在service层接口内添加注解
@Transactional(readOnly = true) public interface AccountService { /** * 转账操作 * @param outName 出账用户名 * @param inName 入账用户名 * @param money 转账金额 */ @Transactional public void transfer(String outName, String inName, Double money); public void findAll(); public void findById(int id); }
4.2.3 纯注解开发
@EnableTransactionManagement
开启注解支持相关的配置说明:
<!--包扫描 IOC-->
<context:component-scan base-package="com.itheima"/>
<!--开启aop注解的支持-->
<aop:aspectj-autoproxy proxy-target-class="true"/>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--事务管理注解驱动-->
<tx:annotation-driven transaction-manager="txManager"/>
重点小结:
-
aop注解
- @Aspect : 声明切面,用在通知类上
- @Before : 前置通知,用在方法上
- @After : 后置通知,用在方法上
- @AfterReturning
- @AfterThrowing
- @Around
- @Pointcut : 切入点:用在空方法上
-
开启aop注解驱动
<aop:aspectj-autoproxy proxy-target-class="true"/>
-
事务控制
- 声明式事务控制(xml|注解)