AOP:动态代理:指在程序运行期间动态的将某段代码切入到指定方法指定位置进行的编程方式
过程:
1导入aop模块
2定义一个业务逻辑类
3定义一个切面类,切面类中的方法需要动态感知业务类的方法运行到哪一步了
通知方法:
前置通知(@Before):在目标方法运行之前运行
后置通知(@After):在目标方法运行之后运行
返回通知(@AfterReturning):在目标方法正常返回之后运行
异常通知(@AfterThrowing):在目标方法出现异常之后运行
环绕通知(@Around):动态代理,手动推进目标方法运行
4给切面类的目标方法标注何时何地运行(通知注解)
5将切面类和目标(业务逻辑类)加入容器中
6告诉spring,哪个是切面类,给切面类上加一个注解,在切面类头上加一个@Aspect,告诉spring这是切面类
7 开启注解自动代理,在配置类上,@EnableAspectJAutoProxy开启基于注解的aop模式
注意!1:不要自己new一个对象出来,要用spring管理的对象
在spring中有很多的@EnableXXXX;都是开启某一项功能
AOP原理
看给容器中注册了什么组件,这个组件什么时候工作,这个组件的功能是什么
@EnableAspectJAutoProxy 加了他才开启了aop
1@EnableAspectJAutoProxy是什么?
@Import(AspectJAutoProxyRegistrar.class)给容器中导入AspectJAutoProxyRegistrar,利用AspectJAutoProxyRegistrar自定义给容器注册了Bean,这个bean是AnnotationAwareAspectJAutoProxyCreator==注解装配模式AspectJ自动代理创建器
2 AnnotationAwareAspectJAutoProxyCreator他的父类是AspectJAwareAdvisorAutoProxyCreator,它的父类是AbstractAdvisorAutoProxyCreator,他的父类是AbstractAutoProxyCreator 它实现了SmartInstantiationAwareBeanProcessor(Bean的后置处理器),
BeanFactorAware,自动装配beanFactory
关注后置处理器的工作,在bean初始化完成前后做的事情,自动装配beanFactory,也就是说AnnotationAwareAspectJAutoProxyCreator重要点在后置处理器和自动装配BeanFactory
AbstractAutoProxyCreator.setBeanFactory()
AbstractAutoProxyCreator有后置处理器的逻辑
AbstractAdvisorAutoProxyCreator.setBeanFactory()里面调用initBeanFactory()
AnnotationAwareAspectJAutoProxyCreator.initBeanFactory()
流程:
1传入配置了类,创建ioc容器
2 注册配置类,调用refresh()刷新容器,
3 注册bean的后置处理器来方便拦截bean的创建
1 先获取ioc容器中已经定义了的但是还没创建对象,需要创建的,对象的所有的BeanPostProcessor
2 给容器中加别的BeanPostProcessor
3 优先注册实现了PriorityOrderded接口的BeanPostProcessor,
4 再注册实现了Ordered接口的BeanPostProcessor
5 再注册没实现优先级接口的BeanPostProcessor
6 注册BeanPostProcessor,实际上上就是创建BeanPostProcessor对象,保存在容器中:
创建initernalAutoProxyCreator[类型是AnnotationAwareAspectJAutoProxyCreator]的BeanPostProcessor
1)创建bean的实例
2)populateBean 给bean的各种属性赋值
3)initializeBean 初始化bean,
1.invokeAwareMethods():处理Aware接口的方法回调
2.执行后置处理器的postProcessBeforeInitialzation();初始化之前的操作
3.invokeInitMethods()执行自定义的初始化方法,
4.执行后置处理器的postProcessAfterInitialzation();初始化之后的操作
4)BeanPostProcessor[AnnotationAwareAspectJAutoProxyCreator]创建成功
g 把BeanPostProcessor注册到BeanFactory中,使用beanFactory.addBeanPostProcessor(postProcessor)方法;
以上是创建和注册AnnotationAwareAspectJAutoProxyCreator(他是后置处理器)的过程
AnnotationAwareAspectJAutoProxyCreator作为后置处理器接下来做了什么?
AnnotationAwareAspectJAutoProxyCreator他是InstantiationAwareBeanPostProcessor类型的后置处理器,他会在所有bean创建之前拦截,尝试返回一个bean实例,方便接下来bean的创建
4 完成BeanFactory初始化工作,创建剩下的单实例Bean
1)遍历获取容器中所有的Bean,依次创建对象,getBean(beanName)->doGetBean()->getSingleton()->
2) 创建bean
1.先从缓存中获取当前Bean,如果能获取到,说明是之前创建过的,直接使用,否则再创建,只要被创建好的bean都会被缓存起来
[BeanPostProcessor是在Bean对象创建完成初始化前后调用的]
[InstantiationAwareBeanPostProcessor就是AnnotationAwareAspectJAutoProxyCreator是在创建bean实例之前尝试使用后置处理器返回一个对象]
2.createBean() 创建bean
1… 希望后置处理器在此能返回一个代理对象,如果能返回就使用,如果不能就继续
2… 调用doCreateBean(),真正的创建一个bean实例,和3.6中的创建bean实例一样
AnnotationAwareAspectJAutoProxyCreator他是InstantiationAwareBeanPostProcessor类型的后置处理器,它的作用是(判断这个bean是否需要包装=即需不需要增强,生成代理对象):
1)每一个bean创建之前,调用 postProcessBeforeInstantiation方法
关心MathCaluculator和LogAspect的创建
1)判断当前bean是否在advisedBean中,(保存了所有需要增强Bean需要被切的)
2)判断当前Bean是否是基础类型的Advice的bean通过判断你实现不实现这些接口,是否切面==通过判断你是否有@Aspect注解
3)是否需要跳过 获取候选的增强器(切面里的通知方法)永远返回false
2)创建对象
postProcessAfterInitialization:return wrapIfNecessary();包装如果需要的情况下:
1)获取当前bean所有的增强器(通知方法)
1、找到候选的所有的增强器(找那些通知发放是需要切入当前Bean方法的)
2、获取到能在bean使用的增强器
3、给增强器排序
2)保存当前bean在advisedBeans
3)如果当前bean需要增强,创建当前bean的代理对象
1。获取所有增强器(通知方法)
2. 保存到proxyFactory
3. 创建代理对象,spring自动决定创建哪种代理对象,一种是JDK形式(JDK动态代理)的,
一种是Cglib形式(Cglib动态代理)的
4.给容器中返回当前组件使用Cglib增强过的代理对象
5.以后容器拿到的就是找个组件的代理对象,执行目标方法的时候,代理对象就会执行通知方法的流程
3)目标方法的执行
容器中保存了组件的代理对象(cglib增强后的对象),这个对象里面保存了详细信息(比如增强器,比如目标对象)
1)CglibAopProxy.intercept();拦截目标方法的执行
2)根据ProxyFactory对象获取将要执行目标方法的拦截器链
1、List<Object>interceptorList 保存所有拦截器,长度是5,一个默认的和4个增强器
2、遍历所有的增强器,封装成Interceptor
3、增强器转为List < MethodInterceptor>,如果是MethodInterceptor,直接加入集合中,如果不是,使用增强器的适配器将增强器转为MethodInterceptor,转换完成,返回MethodInterceptor数组
拦截器链(每一个通知方法又被包装为方法拦截器,利用MethodInterceptor机制)
3)如果没有拦截器链,直接执行目标方法,利用反射
4)如果有拦截器链,把需要执行的目标对象,目标方法拦截器链等信息创建一个CglibMethodInvocation对象
并调用Object retVal =CglibMethodInvocation.proceed()执行方法;
5)拦截器链的触发过程:如果没有拦截器执行目标方法,或者执行拦截器的索引等于拦截器数组-1(指定到了最后一个拦截器),执行目标方法
拦截器索引从-1开始,先自增后找到那个默认的拦截器 >invoke(this)>CglibMethodInvocation.proceed()>找下一个拦截器,通过这种循环将所有的拦截器链起来(前一个拦截器进入下一个,返回的时候再返回,所以前置通知的拦截器在最底层,类似于递归调用那种),到最后一个的时候,先执行前置通知的方法,再CglibMethodInvocation.proceed(),它的索引=拦截器链的长度-1了,就通过反射执行目标方法,再执行后置通知,如果有异常,AfterReturnAdviceInterceptor没有能力捕获异常,就往上抛,给AspectJAfterThrowingAdvice,处理异常
总结:
1)利用@EnableAspectJAutoProxy开启aop功能
2)EnableAspectJAutoProxy会给容器中注册一个AnnotationAwareAspectJAutoProxyCreator
3)AnnotationAwareAspectJAutoProxyCreator是一个后置处理器
4)容器的创建流程:
1)registerBeanPostProcessors()注册后置处理器,创建AnnotationAwareAspectJAutoProxyCreator
2)容器刷新,初始化剩下的单实例Bean
1)创建业务逻辑组件和切面组件
2)AnnotationAwareAspectJAutoProxyCreator会拦截组件的创建过程
3)组件创建完之后,AnnotationAwareAspectJAutoProxyCreator会判断组件是否需要包装(需要增强)如果是,就把切面的通知方法包装成增强器(Advisor),给业务逻辑组件创建一个代理对象(默认是Cglib,有接口也可以用JDK)
5)执行目标方法:
1)代理对象执行目标方法
2)CglibAopProxy.intercept():
1)得到目标方法的拦截器链(增强器包装成拦截器MethodInterceptor)
2)利用拦截器链机制来依次进入每一个拦截器进行执行:
3)效果:
正常执行:前置通知-->目标方法-->后置通知-->返回通知
异常执行:前置通知-->目标方法-->后置通知-->异常通知
AOP声明式事务
方法一旦出现异常,回滚
1 在方法头上加注解@Transactional,spring就会对这个方法进行事务控制,如果方法正常执行,就提交,如果出现异常,所有的方法都会滚
2 注意,要加@EnableTransactionManagement开启基于注解的事务管理
3 配置事务管理器控制事务
原理:
@EnableTransactionManagement
利用@import TransactionManagementConfigurationSelector 给容器中导入组件(因为是selector,会返回需要导入的组件的全类名)
导入两个组件:1个是AutoProxyRegistrar,ProxyTransactionManagementConfiguration
2AutoProxyRegistrar:给容器注册一个InfrastructureAdvisorAutoProxyCreator 的组件(基本的增强代理创建器),和AnnotationAwareAspectJAutoProxyCreator一样也是一个后置处理器
利用后置处理器机制,在对象创建之后,包装对象,返回一个代理对象(里面有增强器,拦截器链),代理对象执行方法利用拦截器链进行调用
3ProxyTransactionManagementConfiguration:
1给容器中注册**事务增强器**,要用事务注解的信息
2给容器中注册**事务拦截器**保存了事务的属性信息,事务管理器,他是一个MethodInterceptor,在目标方法执行的时候,执行拦截器链(和aop原理一样):里面只有一个事务拦截器:先获取事务相关的属性,再获取PlatformTransactionManager,如果事先没有添加指定TransactionManager,他会从容器按照类型获取一个TransactionManager,叫PlatformTransactionManager
3执行目标方法,如果异常,获取到事务管理器,利用事务管理器回滚这次操作,一切正常,用事务管理器提交事务