【spring注解驱动开发】- AOP源码分析

文章目录

  • 1 @EnableAspectJAutoProxy注解做了什么?
    • 1.1 传入配置类,创建IOC容器
    • 1.2 注册配置文件,刷新容器
    • 1.3 注册bean的后置处理器
      • 1.3.1 从容器中获取所有已经定义好了的BeanPostProcessor
      • 1.3.2 注册其他BeanPostProcessor组件
      • 1.3.3 分离BeanPostProcessor组件
      • 1.3.4 注册BeanPostProcessor组件
      • 1.3.5 注册BeanPostProcessor组件,实际上是创建BeanPostProcessor
        • 1.3.5.1 创建bean
        • 1.3.5.2 给bean的属性赋值
        • 1.3.5.3 初始化bean
          • 1.3.5.3.1 处理Aware接口的回调方法
          • 1.3.5.3.2 执行后置处理的postProcessBeforeInitialization()方法
          • 1.3.5.3.3 真正初始化bean操作
          • 1.3.5.3.4 执行后置处理的postProcessAfterInitialization()方法
      • 1.3.6 把BeanPostProcessor注册到BeanFactory中
  • 2 AnnotationAwareAspectJAutoProxyCreator组件的执行时机
    • 2.1 分析finishBeanFactoryInitialization(beanFactory)
      • 2.1.1 创建单实例bean
        • 2.1.1.1 先从缓存中取单实例bean
        • 2.1.1.2 createBean()
        • 2.1.1.3 doCreateBean()
  • 3 AnnotationAwareAspectJAutoProxyCreator组件的作用
    • 3.1 postProcessBeforeInstantiation()
      • 3.1.1 判断当前bean是否在advisedBeans中
      • 3.1.2 判断当前bean是否是基础类型
      • 3.1.3 是否需要跳过
    • 3.2 postProcessAfterInitialization()
      • 3.2.1 如果bean有增强器就为bean创建一个代理类
        • 3.2.1.1 获取bean的所有增强器
        • 3.2.1.2 对增强器排序
        • 3.2.1.3 将需要增强的bean保存在advisedBeans列表中
        • 3.2.1.4 将需要增强的bean创建一个代理类
    • 3.3 目标方法执行
    • 3.4 拦截器链的触发过程
  • 4 总结

本博客demo源码地址
https://github.com/suchahaerkang/spring-annotation.git

上一篇博客,我们测试一下spring AOP功能,知道了如果要使用spring注解驱动开发aop的功能,必须要在配置类上加上@EnableAspectJAutoProxy注解开启切面动态代理功能,我们现在就以@EnableAspectJAutoProxy注解为入口,研究这个入口到底为我们向spring容器注册了什么组件?这组件在什么时候执行和这组件给我们实现了什么功能?

1 @EnableAspectJAutoProxy注解做了什么?

点进@EnableAspectJAutoProxy注解的源码可以看到是使用@Import注解给我们向容器中注册了一个AspectJAutoProxyRegistrar的组件。不知道@Import这个注解的的作用,可以看一下我这篇博客
【spring注解驱动开发】- AOP源码分析_第1张图片
那么AspectJAutoProxyRegistrar这个组件又是什么呢?我们再继续点进去看看,发现这个组件实现了ImportBeanDefinitionRegistrar接口,前面我们学习到ImportBeanDefinitionRegistrar这个接口提供的registerBeanDefinitions()方法可以让我们进行手动注册一些组件到容器中去。
【spring注解驱动开发】- AOP源码分析_第2张图片
然后我们看一下registerBeanDefinitions()这个方法里面做了一些什么操作
【spring注解驱动开发】- AOP源码分析_第3张图片
我们再进一下registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法,看一下给我们注册了什么组件。
【spring注解驱动开发】- AOP源码分析_第4张图片
从源码中我们可以看到,给我们注册了一个叫做AnnotationAwareAspectJAutoProxyCreator的组件,然后我们看一下registerOrEscalateApcAsRequired()这个方法是怎么注册AnnotationAwareAspectJAutoProxyCreator组件的。

【spring注解驱动开发】- AOP源码分析_第5张图片
我们回过来看一下AnnotationAwareAspectJAutoProxyCreator这个组件到底是一个什么样的组件,我们进行源码跟踪
AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware,没有必要的源码图我就不截出来看了,我们发现AnnotationAwareAspectJAutoProxyCreator这个组件最后实现了SmartInstantiationAwareBeanPostProcessorBeanFactoryAware组件。SmartInstantiationAwareBeanPostProcessor 组件是个后置处理器,在bean初始化前后处理事情;BeanFactoryAware组件可以动态向bean注入BeanFactory组件
【spring注解驱动开发】- AOP源码分析_第6张图片
好了,上面我们是通过@EnableAspectJAutoProxy作为入口来查看源码分析了@EnableAspectJAutoProxy注解给我们向容器中注入了一个AnnotationAwareAspectJAutoProxyCreator组件并且这个组件实现了SmartInstantiationAwareBeanPostProcessorBeanFactoryAware组件。下面我们通过debug模式看源码,从容器的创建开始分析AnnotationAwareAspectJAutoProxyCreator的创建过程

1.1 传入配置类,创建IOC容器

【spring注解驱动开发】- AOP源码分析_第7张图片

1.2 注册配置文件,刷新容器

【spring注解驱动开发】- AOP源码分析_第8张图片

1.3 注册bean的后置处理器

【spring注解驱动开发】- AOP源码分析_第9张图片

1.3.1 从容器中获取所有已经定义好了的BeanPostProcessor

【spring注解驱动开发】- AOP源码分析_第10张图片

1.3.2 注册其他BeanPostProcessor组件

【spring注解驱动开发】- AOP源码分析_第11张图片

1.3.3 分离BeanPostProcessor组件

【spring注解驱动开发】- AOP源码分析_第12张图片

1.3.4 注册BeanPostProcessor组件

【spring注解驱动开发】- AOP源码分析_第13张图片

1.3.5 注册BeanPostProcessor组件,实际上是创建BeanPostProcessor

1.3.5.1 创建bean

【spring注解驱动开发】- AOP源码分析_第14张图片

1.3.5.2 给bean的属性赋值

1.3.5.3 初始化bean

【spring注解驱动开发】- AOP源码分析_第15张图片

1.3.5.3.1 处理Aware接口的回调方法

【spring注解驱动开发】- AOP源码分析_第16张图片

1.3.5.3.2 执行后置处理的postProcessBeforeInitialization()方法
1.3.5.3.3 真正初始化bean操作
1.3.5.3.4 执行后置处理的postProcessAfterInitialization()方法

【spring注解驱动开发】- AOP源码分析_第17张图片

1.3.6 把BeanPostProcessor注册到BeanFactory中

【spring注解驱动开发】- AOP源码分析_第18张图片

2 AnnotationAwareAspectJAutoProxyCreator组件的执行时机

上面了解了AnnotationAwareAspectJAutoProxyCreator组件的创建过程,那么AnnotationAwareAspectJAutoProxyCreator组件什么时候执行呢?我们通过看源码知道AnnotationAwareAspectJAutoProxyCreator 最终继承了 InstantiationAwareBeanPostProcessorInstantiationAwareBeanPostProcessor后置处理器有有两个方法postProcessBeforeInstantiation()和postProcessAfterInstantiation(),这两个方法和BeanPostProcessor后置处理的两个方法postProcessBeforeInitialization()和postProcessAfterInitialization()有点类似,我们前面的博客知道BeanPostProcessor后置处理时机是bean的初始化前后作的处理,那么InstantiationAwareBeanPostProcessor后置处理器又是在什么时机进行处理的呢?下面我们debug看一下源码,上面创建和注册AnnotationAwareAspectJAutoProxyCreator组件走完之后即1.3 注册bean的后置处理器这个步骤走完之后,下面来到了finishBeanFactoryInitialization(beanFactory)这个流程
【spring注解驱动开发】- AOP源码分析_第19张图片

2.1 分析finishBeanFactoryInitialization(beanFactory)

进到finishBeanFactoryInitialization(beanFactory)方法中发现,其实就是遍历获取容器中所有的Bean,依次创建对象getBean(beanName)。主要流程是getBean() -> doGetBean() -> getSingleton()

2.1.1 创建单实例bean

2.1.1.1 先从缓存中取单实例bean

【spring注解驱动开发】- AOP源码分析_第20张图片

2.1.1.2 createBean()

【spring注解驱动开发】- AOP源码分析_第21张图片
我们再点进这个方法看一下
【spring注解驱动开发】- AOP源码分析_第22张图片
继续点进resolveBeforeInstantiation() 方法
【spring注解驱动开发】- AOP源码分析_第23张图片

继续点进applyBeanPostProcessorsBeforeInstantiation() 方法,里面做了什么。点进去看后发现里面在遍历
容器中的InstantiationAwareBeanPostProcessor组件,然后调用他们的postProcessBeforeInstantiation()方法
【spring注解驱动开发】- AOP源码分析_第24张图片
到这里我们就知道了InstantiationAwareBeanPostProcessor组件即AnnotationAwareAspectJAutoProxyCreator组件的执行时机是在创建单实例之前

2.1.1.3 doCreateBean()

doCreateBean() 这个方法就是真正的开始创建bean了,整个流程和1.3.5的流程一样。

3 AnnotationAwareAspectJAutoProxyCreator组件的作用

上一节我们分析了在spring中创建所有的bean之前都会被AnnotationAwareAspectJAutoProxyCreator(InstantiationAwareBeanPostProcessor)组件的postProcessBeforeInstantiation()和postProcessAfterInstantiation()方法拦截,那么这两个方法到底做了什么呢?我们现在就开始拦截MathCalculator(目标类)组件和LogAspects(切面类)组件的创建

3.1 postProcessBeforeInstantiation()

每一个bean的创建都会被postProcessBeforeInstantiation()拦截,我们看一下里面做了什么?

3.1.1 判断当前bean是否在advisedBeans中

【spring注解驱动开发】- AOP源码分析_第25张图片

3.1.2 判断当前bean是否是基础类型

判断当前bean是否是基础类型其实就是判断当前组件的父类是否是Advice,Pointcut,Advisor,AopInfrastructureBean或是否为切面类即标注了@AspectJ注解
【spring注解驱动开发】- AOP源码分析_第26张图片

【spring注解驱动开发】- AOP源码分析_第27张图片

3.1.3 是否需要跳过

进入shouldSkip()方法
【spring注解驱动开发】- AOP源码分析_第28张图片
MathCalculate组件在上面的判断都是false,所以创建MathCalculate组件之前没有对其进行什么处理。然后开始创建MathCalculate组件
【spring注解驱动开发】- AOP源码分析_第29张图片
创建MathCalculate之后,在初始化MathCalculate组件之后会被BeanPostProcessor组件的postProcessAfterInitialization()方法拦截,然后我们就分析一下postProcessAfterInitialization()方法里面操作

3.2 postProcessAfterInitialization()

【spring注解驱动开发】- AOP源码分析_第30张图片
点进wrapIfNecessary()方法看看源码
【spring注解驱动开发】- AOP源码分析_第31张图片

3.2.1 如果bean有增强器就为bean创建一个代理类

首先进入findEligibleAdvisors()方法
【spring注解驱动开发】- AOP源码分析_第32张图片
然后进入findAdvisorsThatCanApply() ->findAdvisorsThatCanApply()方法
【spring注解驱动开发】- AOP源码分析_第33张图片
【spring注解驱动开发】- AOP源码分析_第34张图片

3.2.1.1 获取bean的所有增强器

【spring注解驱动开发】- AOP源码分析_第35张图片

3.2.1.2 对增强器排序

【spring注解驱动开发】- AOP源码分析_第36张图片

3.2.1.3 将需要增强的bean保存在advisedBeans列表中

【spring注解驱动开发】- AOP源码分析_第37张图片

3.2.1.4 将需要增强的bean创建一个代理类

【spring注解驱动开发】- AOP源码分析_第38张图片
【spring注解驱动开发】- AOP源码分析_第39张图片
进入getProxy()方法
【spring注解驱动开发】- AOP源码分析_第40张图片
继续进入createAopProxy()方法
【spring注解驱动开发】- AOP源码分析_第41张图片
继续进入createAopProxy()方法,我们可以看到有两种方法动态的创建代理类:1)通过jdk提供的api,这种方式要求被代理的类必须要实现一个接口;2)Cglib的方式。想了解代理模式可以参考我这篇博客
【spring注解驱动开发】- AOP源码分析_第42张图片
最后给容器中返回当前组件MathCalculate使用cglib增强了的代理对象。然后当从容器中获取这个组件的时候,其实获取的是一个MathCalculate的代理类,当我们调用MathCalculate组件的方法时,其实是通过代理类去操控组件的方法,所以可以为组件功能增强。

3.3 目标方法执行

上面我们知道AnnotationAwareAspectJAutoProxyCreator组件作为一个BeanPostProcessor在MathCalculate初始化之后,调用其postProcessAfterInitialization()方法判断MathCalculate组件需要增强吧,如果需要增强,那么就给MathCalculate组件创建了代理对象,下面我们从容器中获取MathCalculate组件,然后执行它的方法。
【spring注解驱动开发】- AOP源码分析_第43张图片
下面执行MathCalculate组件的div()方法,看看里面是怎么执行那些切面的通知方法的?首先是被CglibAopProxy的intercept()拦截
【spring注解驱动开发】- AOP源码分析_第44张图片
我们再看一下获取拦截器链的方法
【spring注解驱动开发】- AOP源码分析_第45张图片
判断拦截器链是否为空作出相应处理
【spring注解驱动开发】- AOP源码分析_第46张图片

3.4 拦截器链的触发过程

【spring注解驱动开发】- AOP源码分析_第47张图片
然后将拦截器链封装到CglibMethodInvocation中,调用proceed()方法触发拦截器链,我们点击去看看里面的执行过程
【spring注解驱动开发】- AOP源码分析_第48张图片
下面画个图来说明一下拦截器链的触发过程
【spring注解驱动开发】- AOP源码分析_第49张图片

4 总结

实现Spring AOP 注解驱动的原理

  • 首先在配置类上标注@EnableAspectJAutoProxy注解,开启AOP功能
  • @EnableAspectJAutoProxy 会给容器中注册一个组件 AnnotationAwareAspectJAutoProxyCreator
  • AnnotationAwareAspectJAutoProxyCreator是一个后置处理器
  • 容器的创建流程:
    • IOC容器创建过程:
    • registerBeanPostProcessors() 注册后置处理器;创建AnnotationAwareAspectJAutoProxyCreator对象
    • finishBeanFactoryInitialization() 初始化剩下的单实例bean
      • 创建业务逻辑组件和切面组件
      • AnnotationAwareAspectJAutoProxyCreator拦截组件的创建过程
      • 组件创建完之后,判断组件是否需要增强
      • 组件创建完之后,判断组件是否需要增强 。是:切面的通知方法,包装成增强器(Advisor);给业务逻辑组件创建一个代理对象(cglib)
  • 执行目标方法:
    • 代理对象执行目标方法
    • CglibAopProxy.intercept()
      • 得到目标方法的拦截器链(增强器包装成拦截器MethodInterceptor)
      • 利用拦截器的链式机制,依次进入每一个拦截器进行执行
      • 效果:正常执行:前置通知-》目标方法-》后置通知-》返回通知;出现异常:前置通知-》目标方法-》后置通知-》异常通知

你可能感兴趣的:(spring)