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

文章目录

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

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

1 @EnableAspectJAutoProxy注解做了什么?

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

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

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

在这里插入图片描述

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

在这里插入图片描述

1.3 注册bean的后置处理器

在这里插入图片描述

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

在这里插入图片描述

1.3.2 注册其他BeanPostProcessor组件

在这里插入图片描述

扫描二维码关注公众号,回复: 10156204 查看本文章

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组件的执行时机

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

2.1 分析finishBeanFactoryInitialization(beanFactory)

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

2.1.1 创建单实例bean

2.1.1.1 先从缓存中取单实例bean

在这里插入图片描述

2.1.1.2 createBean()

在这里插入图片描述
我们再点进这个方法看一下
在这里插入图片描述
继续点进resolveBeforeInstantiation() 方法
在这里插入图片描述

继续点进applyBeanPostProcessorsBeforeInstantiation() 方法,里面做了什么。点进去看后发现里面在遍历
容器中的InstantiationAwareBeanPostProcessor组件,然后调用他们的postProcessBeforeInstantiation()方法
在这里插入图片描述
到这里我们就知道了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中

在这里插入图片描述

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

判断当前bean是否是基础类型其实就是判断当前组件的父类是否是Advice,Pointcut,Advisor,AopInfrastructureBean或是否为切面类即标注了@AspectJ注解
在这里插入图片描述

在这里插入图片描述

3.1.3 是否需要跳过

进入shouldSkip()方法
在这里插入图片描述
MathCalculate组件在上面的判断都是false,所以创建MathCalculate组件之前没有对其进行什么处理。然后开始创建MathCalculate组件
在这里插入图片描述
创建MathCalculate之后,在初始化MathCalculate组件之后会被BeanPostProcessor组件的postProcessAfterInitialization()方法拦截,然后我们就分析一下postProcessAfterInitialization()方法里面操作

3.2 postProcessAfterInitialization()

在这里插入图片描述
点进wrapIfNecessary()方法看看源码
在这里插入图片描述

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

首先进入findEligibleAdvisors()方法
在这里插入图片描述
然后进入findAdvisorsThatCanApply() ->findAdvisorsThatCanApply()方法
在这里插入图片描述
在这里插入图片描述

3.2.1.1 获取bean的所有增强器

在这里插入图片描述

3.2.1.2 对增强器排序

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述
在这里插入图片描述
进入getProxy()方法
在这里插入图片描述
继续进入createAopProxy()方法
在这里插入图片描述
继续进入createAopProxy()方法,我们可以看到有两种方法动态的创建代理类:1)通过jdk提供的api,这种方式要求被代理的类必须要实现一个接口;2)Cglib的方式。想了解代理模式可以参考我这篇博客
在这里插入图片描述
最后给容器中返回当前组件MathCalculate使用cglib增强了的代理对象。然后当从容器中获取这个组件的时候,其实获取的是一个MathCalculate的代理类,当我们调用MathCalculate组件的方法时,其实是通过代理类去操控组件的方法,所以可以为组件功能增强。

3.3 目标方法执行

上面我们知道AnnotationAwareAspectJAutoProxyCreator组件作为一个BeanPostProcessor在MathCalculate初始化之后,调用其postProcessAfterInitialization()方法判断MathCalculate组件需要增强吧,如果需要增强,那么就给MathCalculate组件创建了代理对象,下面我们从容器中获取MathCalculate组件,然后执行它的方法。
在这里插入图片描述
下面执行MathCalculate组件的div()方法,看看里面是怎么执行那些切面的通知方法的?首先是被CglibAopProxy的intercept()拦截
在这里插入图片描述
我们再看一下获取拦截器链的方法
在这里插入图片描述
判断拦截器链是否为空作出相应处理
在这里插入图片描述

3.4 拦截器链的触发过程

在这里插入图片描述
然后将拦截器链封装到CglibMethodInvocation中,调用proceed()方法触发拦截器链,我们点击去看看里面的执行过程
在这里插入图片描述
下面画个图来说明一下拦截器链的触发过程
在这里插入图片描述

4 总结

实现Spring AOP 注解驱动的原理

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

猜你喜欢

转载自blog.csdn.net/suchahaerkang/article/details/104791857