Spring AOP
2021-02-23 18:21:33 31 举报
AI智能生成
sping aop 流程分析
作者其他创作
大纲/内容
0.准备工作
1.原理探究
1.开启aop注解:@EnableAspectJAutoProxy
2.给容器导入了 AspectJAutoProxyRegistrar 类,这个类实现了 ImportBeanDefinitionRegistrar接口,向容器中注册 bean
3.最后给容器注册了 AnnotationAwareAspectJAutoProxyCreator 类,bean name = org.springframework.aop.config.internalAutoProxyCreator
4.看下 AnnotationAwareAspectJAutoProxyCreator 类的继承关系
extends AspectJAwareAdvisorAutoProxyCreator 类
extends AbstractAdvisorAutoProxyCreator
extends AbstractAutoProxyCreator
implements SmartInstantiationAwareBeanPostProcessor,BeanFactoryAware
5.关注后置处理器(在bean初始化完成前后做事情)、自动装配BeanFactory
6.由于他的继承关系比较多,而且是从 AbstractAutoProxyCreator 开始是实现了后置处理器和bean工厂,所以我
从这个父类开始找和处理器以及工厂bean相关的方法(可以在这些方法上打上端点,方便观察)
从这个父类开始找和处理器以及工厂bean相关的方法(可以在这些方法上打上端点,方便观察)
6.1)AbstractAutoProxyCreator
setBeanFactory()
postProcessBeforeInstantiation() 在'实例化之前'工作
postProcessAfterInitialization() 在'初始化之后'工作
6.2)AbstractAdvisorAutoProxyCreator
setBeanFactory();说明他重写了此方法,所以 AbstractAutoProxyCreator 实际上会调用这个子类的
initBeanFactory();setBeanFactory() 方法内部调用了 initBeanFactory() 方法,无和处理器相关的方法
6.3)AspectJAwareAdvisorAutoProxyCreator
无相关方法
6.4)AnnotationAwareAspectJAutoProxyCreator
initBeanFactory();在 AbstractAdvisorAutoProxyCreator 中的 setBeanFactory() 内部调用了
initBeanFactory() 方法,而当前类重写了此方法,所以实际上会调用重写后的 initBeanFactory() 方法
initBeanFactory() 方法,而当前类重写了此方法,所以实际上会调用重写后的 initBeanFactory() 方法
2.源码分析
2.1)关注 AnnotationAwareAspectJAutoProxyCreator 处理器对象的创建
2.1.1)AnnotationAwareAspectJAutoProxyCreator 类的注册已经知道了,就是在前面 @EnableAspectJAutoProxy 注解中导入的,因为容器对象 AnnotationConfigApplicationContext 在刷新时,有一步是 调用BeanFactory 的处理器,其中配置类处理器 ConfigurationClassPostProcessor 此时会工作,他会解析配置类上的 @EnableAspectJAutoProxy 注解,将导入的 Bean的定义信息 注册到 BeanFactory 中
2.1.2)AnnotationAwareAspectJAutoProxyCreator 类还是一个 BeanPostProcessor, 所以在容器刷新的 registerBeanPostProcessors() 方法中会创建对象;因为会调用 BeanFactory 的 getBean() 方法,这个方法获取获取不到,就会去创建对象,所以这里会把前面保存的 BeanPostProcessor 类定义信息获取出来,然后创建对象,保存到单例容器 DefaultSingletonBeanRegistry 中
2.1.3)在简要描述下 AnnotationAwareAspectJAutoProxyCreator 对象的创建过程
1. AbstractAutowireCapableBeanFactory.doCreateBean().createBeanInstance() --在这里创建bean的实例
2. AbstractAutowireCapableBeanFactory.populateBean() 给 Bean 的属性赋值
3. AbstractAutowireCapableBeanFactory.initializeBean() 初始化
a.invokeAwareMethods():处理Aware接口的方法回调,AOP的类间接实现了 BeanFactoryAware 接口
b.applyBeanPostProcessorsBeforeInitialization():掉用后置处理器的postProcessBeforeInitialization()
c.invokeInitMethods();执行自定义的初始化方法
d.applyBeanPostProcessorsAfterInitialization();执行后置处理器的postProcessAfterInitialization()
4.在初始化方法中,调用了 invokeAwareMethods() 方法,处理 Aware接口的方法回调,这样他就会来到
AbstractAdvisorAutoProxyCreator 的 setBeanFactory() 方法的断点中,进而来到
AnnotationAwareAspectJAutoProxyCreator 的 initBeanFactory() 方法中。
AbstractAdvisorAutoProxyCreator 的 setBeanFactory() 方法的断点中,进而来到
AnnotationAwareAspectJAutoProxyCreator 的 initBeanFactory() 方法中。
2.2)关注业务对象 LogAspects 和 MathCalculator 的创建,并关注处理器相关的方法
1.重点关注 AbstractAutoProxyCreator 的拦截器方法 postProcessBeforeInstantiation (在每一个bean的实例化之前执行)
1.1)当调用容器刷新方法的 finishBeanFactoryInitialization(); 初始化所有的剩下的单实例bean
1.2)当来到第一个bean的创建时,注意:他先来到 处理器的 postProcessBeforeInstantiation() 方法,因为这个方法所有处理器中最先执行的一个,甚至先于创建bean实例方法。假如这里第一个bean是主配置类 MainConfigOfAOP;
1.3)来到了 AbstractAutoProxyCreator 类的 postProcessBeforeInstantiation()方法(实例化之前执行);有两个重要的判断
1.3.1) 判断当前bean是否是基础类型的 Advice/Pointcut/Advisor/AopInfrastructureBean, 或者是否是切面,即标注了 @Aspect 注解
1.3.2) 是否需要跳过,这个判断方法其实做了非常多的事情
1. 发现候选的增强器 findCandidateAdvisors() ---> aspectJAdvisorsBuilder.buildAspectJAdvisors()
2.从bean定义容器中找到所有的 bean名字,然后遍历,如果某个bean包含 @Aspect 注解
3.获取@Aspect注解标注的当前bean的所有增强器,其实就是这个切面的所有方法
4.找到当前切面的所有方法,除了 @PonintCut 注解标注的以外的所有方法
5.对上述方法进行排序:从源码可以看到是按照:Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class 的顺序进行排序
6.对上述所有方法转换成 Advisor 增强器,具体类型是 InstantiationModelAwarePointcutAdvisorImpl(每个方法new一个)
implements InstantiationModelAwarePointcutAdvisor
extends PointcutAdvisor
extends Advisor
7.在创建 InstantiationModelAwarePointcutAdvisorImpl 对象时,其构造器做了一件事:实例化通知,即 Advice
他会根据当前方法的注解信息(比如:@Before),返回对应的 Advice
环绕通知:AspectJAroundAdvice
前置通知:AspectJMethodBeforeAdvice
后置通知:AspectJAfterAdvice
返回通知:AspectJAfterReturningAdvice;这里也会获取注解的 returning 属性值,并保存到通知中
异常通知:AspectJAfterThrowingAdvice;这里也会获取注解的 throwing 属性值,并保存到通知中
8.最后返回 Advisor 对象,即 InstantiationModelAwarePointcutAdvisorImpl 对象,每一个方法都是 Advisor, 最后将每一个 Advisor 对象保存到 集合中
9.将当前切面类以及他的所有增强器缓存到 advisorsCache 中,key=aspectJbeanName; value=List<Advisor>; 留着后面用
10.最后这个判断方法总是返回false. 从上面可以看到,这个判断方法其实做了非常多,非常重要的事情
2.执行完上面的处理器方法,则来到 AbstractAutoProxyCreator 类的 postProcessAfterInitialization 方法(初始化之后执行); 开始对 bean 进行包装
2.1) getAdvicesAndAdvisorsForBean 获取通知和增强器
1.发现 所有的候选增强器,这个就是前面在 1.3.2 整个步骤中,保存到 advisorsCache 中的信息,所以这里直接从缓存获取
2.发现 当前类 能够应用的增强器,这个方法细节不说了,他的作用就是 看 当前 bean 中的方法是否能够符合 切面类中的方法,就是切面能够作用于当前类,最后返回能够生效的增强器的集合 List<Advisor>
3.如果上面第2步骤可以获取到 能够应用的增强器,则对上述的 List<Advisor> 集合 index = 0 的位置,新增一个增强器 ExposeInvocationInterceptor
2.2) 如果上面可以获取到,则 this.advisedBeans.put(cacheKey, Boolean.TRUE); value 为true,表示是需要增强的bean。因为我当前的bean 是主配置类,他的所有方法中肯定没有符合切面类的,所以最后就是单纯的将 配置类放到 advisedBeans 中,key=beanName, value=false; 当来到 业务类 MathCalculator 创建的时候,此时在上面,可以发现 能够应用的增强器,所以最后返回生效的增强器,并放到 advisedBeans 中,key=beanNmae, value=TRUE; value=TRUE 表示是需要增强的bean(所有的bean都会保存到这里,但value=true 才是需要增强的)
2.3) 如果1.4.1.2)中获取不到能够应用的增强器,即当前bean的方法无法于切面中的通知相匹配,则直接返回当前bean, 比如当前bean是主配置类,则在这里直接返回了
2.4)如果 1.4.1.2)中能够获取到 能应用的增强器,说明当前bean有方法与切面中的通知相匹配,比如业务对象 MathCalculator 就是符合的
1.如果当前bean能找到 能够应用的增强器(就是切面中的方法);则 将 当前bean放到 advisedBeans 中,key=beanName, value=true
2.对当前bean创建代理对象
1. DefaultAopProxyFactory 类创建 Aop 代理
如果实现了接口,则创建 JdkDynamicAopProxy 对象
implements AopProxy
如果没有实现接口,则创建 ObjenesisCglibAopProxy 对象
extends CglibAopProxy implements AopProxy
2.因为 没有实现接口,所以返回 ObjenesisCglibAopProxy 对象,然后通过该对象,创建代理对象。。。。。这里可以看下 CGLIB 如何使用
父类 AopProxy 中有几个内部类
StaticUnadvisedInterceptor implements MethodInterceptor
StaticUnadvisedExposedInterceptor implements MethodInterceptor
DynamicUnadvisedInterceptor implements MethodInterceptor
DynamicUnadvisedExposedInterceptor implements MethodInterceptor
DynamicAdvisedInterceptor implements MethodInterceptor
目标方法会由它来执行,请参考这篇文章
Cglib中的核心对象 Enhancer 的两个重要的属性
1. CallbackFilter filter 属性。具体对象是 ProxyCallbackFilter, 实现了 CallbackFilter 接口,有一个重要的方法:accept(Method method) ; 该方法返回的是一个 int 值,就是下面属性集合的下标
2.Callback[] callbacks; 里面的每一个元素都是实现了 MethodInterceptor 接口,一共有上面那几个类
3.将创建好的 代理对象 放到 proxyTypes 中,key=beanName, value=proxy.getClass()
4.最后返回一个代理对象。所以,业务对象 MathCalculator 实际上保存在单例容器中的是一个 代理对象
2.3)关注目标方法的执行;上面执行完成后,最终返回一个代理对象,由代理对象执行目标方法。这个是难点
1.来到 CglibAopProxy#DynamicAdvisedInterceptor 拦截器的 intercept() 方法
2. List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); 获取拦截器链; method 就是目标方法,targetClass 就是切面作用的类,这里就是 MathCalculator
将 每一个Advisor (获取每一个 Advisor 里面的Advice)转换成 MethodInterceptor,放到集合中
1. index = 0 的 ExposeInvocationInterceptor 实现了 MethodInterceptor
2. index = 1 的 AspectJMethodBeforeAdvice 利用 MethodBeforeAdviceInterceptor 拦截器包装
3. index = 2 的 AspectJAfterAdvice 实现了 MethodInterceptor
4. index = 3 的 AspectJAfterReturningAdvice 利用 AfterReturningAdviceInterceptor 拦截器包装
5. index = 4 的 AspectJAfterThrowingAdvice 实现了 MethodInterceptor
3. 创建 CglibMethodInvocation 对象(extends ReflectiveMethodInvocation),并调用 proceed()方法
链式调用,按照拦截器的顺序执行(即通知方法的顺序执行)
0 条评论
下一页