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