AOP(Aspect Oritented Programming):面向切面变成,通过预编译和运行期动态代理实现程序功能的唯一维护的一种技术。AOP是OOP的延续,也是对OOP的补充。它是Spring框架中的一个重要内容,是函数式变成的一种衍生泛型。利用AOP可以对业务逻辑的各个部分进行隔离,对MVC的垂直架构进行横向切入,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

代理模式

代理模式是GOF23种设计模式之一,为其他对象提供了一个代理以提供对某个对象的访问。
主要包括:

  1. 接口
  2. 被代理类
  3. 代理类

Java实现有静态代理和动态代理。静态代理在编译期实现,动态代理在运行期实现。
下面以演唱会为场景进行演示。

静态代理

首先需要定义一个演唱会接口,定义演唱会的两个功能,开始和结束:

  1. public interface Concert {
  2. void start(String song);
  3. void end(String song);
  4. }

接着创建真实的演唱会,在该类中真正实现演唱会的功能:

  1. public class RealConcert implements Concert {
  2. private Logger log = LoggerFactory.getLogger(this.getClass());
  3. private String singerName;
  4. public RealConcert(String singerName) {
  5. this.singerName = singerName;
  6. }
  7. @Override
  8. public void start(String song) {
  9. log.info("{}演唱会即将开始", singerName);
  10. log.info("第一首:《{}}》", song);
  11. }
  12. @Override
  13. public void end(String song) {
  14. log.info("最后一首:《{}》", song);
  15. log.info("{}演唱会即将结束", singerName);
  16. }
  17. }

因为演唱会是需要场地举办,场地上要进行其他的广告插入和安全措施,通过代理创建最终的演唱会:

  1. public class ProxyRealConcert implements Concert {
  2. private final Logger log = LoggerFactory.getLogger(this.getClass());
  3. private Concert concert;
  4. private String address;
  5. public ProxyRealConcert(Concert concert, String address) {
  6. this.concert = concert;
  7. this.address = address;
  8. }
  9. @Override
  10. public void start(String song) {
  11. startNotice();
  12. concert.start(song);
  13. }
  14. @Override
  15. public void end(String song) {
  16. concert.end(song);
  17. endNotice();
  18. }
  19. private void startNotice() {
  20. log.info("欢迎来到{}看演唱会,荧光棒、粉丝牌9.8折,欢迎购买!", address);
  21. }
  22. private void endNotice() {
  23. log.info("演唱会已经结束,请带走私人物品和垃圾,家长注意看好小孩");
  24. }
  25. }

最后编写测试代码:

  1. public class StaticProxyTest {
  2. public static void main(String[] args) {
  3. // 被代理类
  4. Concert originConcert = new RealConcert("周杰伦");
  5. // 代理类
  6. Concert proxyConcert = new ProxyRealConcert(originConcert, "鸟巢");
  7. proxyConcert.start("花海");
  8. proxyConcert.end("安静");
  9. }
  10. }

运行,控制台输出如下:

  1. 15:33:55.064 [main] INFO top.parak.quiet.SuperRealConcert - 欢迎来到鸟巢看演唱会,荧光棒、粉丝牌9.8折,欢迎购买!
  2. 15:33:55.067 [main] INFO top.parak.quiet.RealConcert - 周杰伦演唱会即将开始
  3. 15:33:55.067 [main] INFO top.parak.quiet.RealConcert - 第一首:《花海》
  4. 15:33:55.067 [main] INFO top.parak.quiet.RealConcert - 最后一首:《安静》
  5. 15:33:55.067 [main] INFO top.parak.quiet.RealConcert - 周杰伦演唱会即将结束
  6. 15:33:55.067 [main] INFO top.parak.quiet.SuperRealConcert - 演唱会已经结束,请带走私人物品和垃圾,家长注意看好小孩

可以看到,代理模式可以在不修改代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。值得注意的是,代理类和被代理类应该共同实现一个接口,或者是共同继承某个抽象类。

动态代理

接口和被代理类与静态代理相同,修改代理类:

  1. public class ProxyRealConcert implements InvocationHandler {
  2. private final Logger log = LoggerFactory.getLogger(this.getClass());
  3. private Object concert;
  4. private String address;
  5. public ProxyRealConcert(Object concert, String address) {
  6. this.concert = concert;
  7. this.address = address;
  8. }
  9. @Override
  10. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  11. if (method.getName().equals("start")) {
  12. startNotice();
  13. method.invoke(concert, args);
  14. } else if (method.getName().equals("end")) {
  15. method.invoke(concert, args);
  16. endNotice();
  17. }
  18. return null;
  19. }
  20. private void startNotice() {
  21. log.info("欢迎来到{}看演唱会,荧光棒、粉丝牌9.8折,欢迎购买!", address);
  22. }
  23. private void endNotice() {
  24. log.info("演唱会已经结束,请带走私人物品和垃圾,家长注意看好小孩");
  25. }
  26. }

测试代码如下:

  1. public class DynamicProxyTest {
  2. public static void main(String[] args) {
  3. // 被代理类
  4. Concert originConcert = new RealConcert("周杰伦");
  5. InvocationHandler invocationHandler = new ProxyRealConcert(originConcert, " 鸟巢");
  6. // 代理类
  7. Concert proxyConcert = (Concert) Proxy.newProxyInstance(RealConcert.class.getClassLoader(), RealConcert.class.getInterfaces(), invocationHandler);
  8. proxyConcert.start("花海");
  9. proxyConcert.end("安静");
  10. }
  11. }

运行启动类,实现效果与静态代理相同。

AOP的术语

在AOP中,切面的工作被称为通知。
通知定义了切面是什么以及何时使用,定义如下:

  1. 连接点(JpinPoint):在应用执行过程中能够插入切面的一个点。这个点是调用方法时,抛出异常时,甚至是修改一个字段时。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。
  2. 切点(Pointcut):切点的定义会匹配通知所要织入的一个或多个连接点。我们通常使用明确的类和方法名称来指定这些切点,或是利用正则表达式定义要匹配的类和方法名称来指定这些切点。
  3. 切面(Aspect):切面是通知和切点的结合。通知和切点共同定义了关于切面的全部内容——它是什么,在何时和何处完成其功能。
  4. 引入(Introdution):引入允许我们向现有的类添加新的方法和属性。
  5. 织入(Weaving):织入是将切面应用到目标对象来创建新的代理对象的过程。切面在指定的连接点被织入到目标对象中。在目标对象的生命周期里有多个点可以进行织入:
    • 编译期:切面在目标类编译期时被织入
    • 类加载期:切面在目标类加载到JVM时被织入
    • 运行期:切面在应用运行的某个时候被织入(Spring使用)

Spring切面可以应用五种类型的通知:

  1. Before:在方法被调用之前调用通知
  2. After:在方法完成之后调用通知,无论方法是否执行成功
  3. After-returning:在方法成功执行之后调用通知
  4. After-throwing:在方法抛出异常之后调用通知
  5. Around:通知包括了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为

AOP的使用

新建项目,引入依赖:

  1. <properties>
  2. <spring.boot.version>2.4.0</spring.boot.version>
  3. </properties>
  4. <dependencies>
  5. <dependency>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter</artifactId>
  8. <version>${spring.boot.version}</version>
  9. </dependency>
  10. <dependency>
  11. <groupId>org.springframework.boot</groupId>
  12. <artifactId>spring-boot-starter-aop</artifactId>
  13. <version>${spring.boot.version}</version>
  14. </dependency>
  15. </dependencies>

创建一个目标类,里面包含需要被AOP代理增强的方法test

  1. @Component
  2. public class TargetClass {
  3. public String test(String value) {
  4. System.out.println(this.getClass().getSimpleName() + ": test()被执行");
  5. if (!StringUtils.hasLength(value)) {
  6. throw new RuntimeException("value不能为空");
  7. }
  8. return "new" + value;
  9. }
  10. }

编写切面类:

  1. @Aspect
  2. @Component
  3. public class MyAspect {
  4. @Pointcut("execution(public * top.parak.TargetClass.test(..))")
  5. public void pointcut() {
  6. }
  7. @Before("pointcut()")
  8. public void onBefore(JoinPoint joinPoint) {
  9. System.out.println("onBefore: " + joinPoint.getSignature().getName() +
  10. "()开始执行,参数:" + Arrays.asList(joinPoint.getArgs()));
  11. }
  12. @After("pointcut()")
  13. public void onAfter(JoinPoint joinPoint) {
  14. System.out.println("onAfter: " + joinPoint.getSignature().getName() +
  15. "()执行结束,参数:" + Arrays.asList(joinPoint.getArgs()));
  16. }
  17. @AfterReturning(value = "pointcut()", returning = "result")
  18. public void afterReturning(JoinPoint joinPoint, Object result) {
  19. System.out.println("afterReturning: " + joinPoint.getSignature().getName() +
  20. "()执行返回,参数:" + Arrays.asList(joinPoint.getArgs()) + ",返回值:" + result);
  21. }
  22. @AfterThrowing(value = "pointcut()", throwing = "exception")
  23. public void afterThrowing(JoinPoint joinPoint, Exception exception) {
  24. System.out.println("afterThrowing: " + joinPoint.getSignature().getName() +
  25. "()执行出错,参数:" + Arrays.asList(joinPoint.getArgs()) + ",异常:" + exception.getMessage());
  26. }
  27. }

该切面包含了4个通知方法:

  1. 前置通知(@Before):在目标方法调用之前调用通知
  2. 后置通知(@After):在目标方法完成之后调用通知
  3. 返回通知(@AfterReturning):在目标方法成功执行之后通知
  4. 异常通知(@AfterThrowing):在目标方法抛出异常之后通知

通知是顺序在不同的Spring版本中会有所不同:

  • Spring4.x
    1. 正常情况:@Before —> 目标方法 —> @After —> @AfterReturning
    2. 异常情况:@Before —> 目标方法 —> @After —> @AfterThrowing
  • Spring5.x
    1. 正常情况:@Before —> 目标方法 —> @AfterReturning —> @After
    2. 异常情况:@Before —> 目标方法 —> @AfterThrowing —> @After

编写SpringBoot启动类:

  1. @SpringBootApplication
  2. public class AOPApplication {
  3. public static void main(String[] args) {
  4. ConfigurableApplicationContext applicationContext = SpringApplication.run(AOPApplication.class, args);
  5. TargetClass targetClass = applicationContext.getBean(TargetClass.class);
  6. targetClass.test("aop");
  7. targetClass.test("");
  8. }
  9. }

执行结果如下:

  1. # 参数:"aop"
  2. onBefore: test()开始执行,参数:[aop]
  3. TargetClass: test()被执行
  4. afterReturning: test()执行返回,参数:[aop],返回值:newaop
  5. onAfter: test()执行结束,参数:[aop]
  6. # 参数:""
  7. onBefore: test()开始执行,参数:[]
  8. TargetClass: test()被执行
  9. afterThrowing: test()执行出错,参数:[],异常:value不能为空
  10. onAfter: test()执行结束,参数:[]

@EnableAspectAutoProxy

在前面引入的spring-boot-starter-aop中,@Enable模块驱动注解@EnableAspectJAutoProxy用于开启AspectJ自动代理,源码如下:

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Import(AspectJAutoProxyRegistrar.class)
  5. public @interface EnableAspectJAutoProxy {
  6. boolean proxyTargetClass() default false;
  7. boolean exposeProxy() default false;
  8. }

该注解类通过@Import导入了AspectJAutoProxyRegistrarAspectJ自动代理注册器,查看AspectJAutoProxyRegistrar源码:
image.png
这个类实现了ImportBeanDefinitionRegistrar接口,通过注释可以了解,这个注册器的作用是往IOC容器中注册一个AnnotationAwareAspectJAutoProxyCreator(注解驱动的AspectJ自动代理创建器)的Bean。
重点关注:

  1. AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

查看源码:

  1. @Nullable
  2. public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
  3. return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
  4. }

实际上调用下面方法:
image.png
可以看到,核心逻辑为通过RootBeanDefinition向IOC注册了名称为AUTO_PROXY_CREATOR_BEAN_NAME(常量,值为org.springframework.aop.config.internalAutoProxyCreator),类型为AnnotationAwareAspectJAutoProxyCreator的Bean。
0p’lo

总结:@EnableAspectJAutoProxy模块驱动注解向IOC容器中注册了类型为AnnotationAwareAspectJAutoProxyCreator的bean。

AnnotationAwareAspectJAutoProxyCreator

通过前面的分析,我们的目光聚焦在AnnotationAwareAspectJAutoProxyCreator类上,为了搞清楚这个类的作用,先捋清类的层级关系:
image.png
可以看到AnnotationAwareAspectJAutoProxyCreator的父类AbstractAutoProxyCreator实现了SmartInstantiationAwareBeanPostProcessorBeanFactoryAware接口。实现BeanFactoryAware用于在Bean初始化时注入BeanFactory,而SmartInstantiationAwareBeanPostProcessor接口的父类为InstantiationAwareBeanPostProcessor,该接口继承自BeanPostProcesorBeanPostProcessorInstantiationAwareBeanProcessor接口包含一些用于Bean实例化和初始化前后进行自定义操作的方法,所以可以大体猜测出目标的代理是在这些接口方法中实现的。
查看AbstractAutoProxyCreator的源代码,它实现了BeanPostProcessorInstantiationAwareBeanProcessor接口,重写了InstantiationAwareBeanProcessorpostProcessBeforeInstantiation方法(自定义Bean实例化前的操作逻辑)和BeanPostProcessorpostProcessAfterInitialization方法(自定义Bean初始化后的操作逻辑):
image.png
所以在这两个方法上打上两个断点,用于后续Debug:
image.png

AOP创建代理过程

使用Debug方式启动上述AOP的Demo,因为后置处理器对所有Bean都生效,所以每个Bean创建时都会进入我们刚刚打断点的两个方法中。但我们只关心Spring AOP是如何增强我们的目标类TargetClass的,所以如果Bean类型不是TargetClass,我们直接点击Resume Program跳过,知道Bean类型是TargetClass
image.png
postProcessBeforeInstantiation方法主要包含以下几个核心步骤:
image.png
(1)通过Bean名称和Bean类型获取该Bean的唯一缓存键名,getCache方法源码如下:
image.png
在这里,cacheKey的值为targetClass。
(2)判断当前Bean(TargetClass)是否包含在advisedBeans集合中(AbstractAutoProxyCreator的成员变量)

  1. /** Default is global AdvisorAdapterRegistry. */
  2. private AdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();

advisedBeans用于存放Bean是否需要增强的标记,键为每个Bean的cacheKey,值为布尔类型,true表示需要增强,false表示不需要增强,此时TargetClass还未实例化,所以自然不在该集合中。
(3)判断当前Bean(TargetClass)是否基础类,查看AnnotationAwareAspectJAutoProxyCreatorisInfrastructureClass方法源码:
image.png
其中isInfrastructureClass调用父类方法,如下:
image.png
this.aspectAdvisorFactory.isAspect方法源码如下:
image.png
所以这一步的逻辑为:判断该当前Bean(TargetClass)是否是AdvicePointCutAdvisorAopInfrastructureBean的子类或者是否为切面类(被@Aspect注解标注)。
(4)判断是否需要跳过,shouldSkip方法源码如下:
image.png
image.png
通过Bean名称判断是否以AutowireCapableBeanFactory._ORIGINAL_INSTANCE_SUFFIX_(.ORIGINAL)结尾,是的话返回true代表跳过处理。
显然,TargetClass不符合3和4,继续走第5步。
(5)如果我们自定义了TargetSource,则在此处理Bean代理,以取代目标Bean的后续默认实例化方式。我们并没有自定义TargetClass,所以直接跳过。

经过以上五步,就TargetClass这个Bean而言,postProcessBeforeInstantiation方法最终返回null。Bean实例化前置处理到此完毕,点击Resume Program,继续Bean的后续生命周期处理逻辑,程序跳转到Bean初始化后置处理方法postProcessAfterInitialization
image.png
重点关注wrapIfNecessary方法,查看wrapIfNecessary方法源码:
image.png
(1)getAdvicesAndAdvisors方法内部主要包含以下这些逻辑:

  1. 获取所有的通知方法(切面里定义的各个方法);
  2. 通过切点表达式判断这些通知方法是否为当前Bean所用;
  3. 如果有符合的通知方法,则对它们进行排序(排序规则不同版本Spring有所不同,上面已经提及)。

在前面的AOP例子中,切面MyAspect里的通知方法就是为了增强TargetClass所设的(根据切点表达式),所以getAdvicesAndAdvisorsForBean方法返回值如下所示:
image.png
这些通知方法就是我们在MyAspect切面里定义的通知方法。
(2)如果该Bean的通知方法集合不为空的话,则创建该Bean的代理对象,具体查看createProxy方法源码:
image.png
继续跟踪proxyFactory.getProxy(getProxyClassLoader())源码:
image.png
image.png
image.png
Spring会判断当前使用哪种代理对象(一般来说Bean有实现接口时,使用JDK动态代理,当Bean没有实现接口时,使用Cglib动态代理。在SpirngBoot中,我们可以通过spring.aop.proxy-target-class=true配置来强制使用Cglib代理)。
image.png
后续从IOC容器中获得的TargetClass就是被代理后的对象,执行代理对象的目标方法的时候,代理对象会执行相应的通知方法链。

生成拦截器链

AOP代理对象生成后,我们接着关注代理对象的目标方法执行时,通知方式是怎么被执行的。
先将前面的所有断点去掉,然后在AOPApplication的如下位置打上断点:
image.png
再次以Debug方式启动程序,可以看到获取到的TargetClass就是前面Cglib代理后的Bean:
image.png
点击Step Into进入test方法内部调用逻辑,会发现程序跳转到了CglibAopProxyintercept方法中,也就是说我们的目标对象的目标方法中,也就是说我们的目标对象的目标方法被CglibAopProxyintercept方法拦截了,该拦截方法主要逻辑如下:
image.png
这里重点关注getInterceptorsAndDynamicInterceptionAdvice方法,源码如下:
image.png

所谓的拦截器链,就是在代理对象的某个方法被执行时,从通知方法集合(创建代理对象的时候就已经通知集合保存在代理对象中了)中筛选出适用于该方法的通知,然后封装为拦截器对象集合(类型为MethodInterceptor)。

继续查看this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice方法源码:
image.png
intercept方法的this.advised.getInterceptorsAndDynamicInterceptionAdvice_(_method, targetClass_)_这一行打个断点,点击Resume Program,看到拦截器链的内容如下:
image.png
拦截器链第一个元素类型为ExposeInvocationInterceptor,是默认的拦截器,后面会详细介绍。
剩下四个类型依次为:

  • MethodBeforeAdviceInterceptor
  • AspectJAfterAdvice
  • AfterReturningAdviceInterceptor
  • AspectJAfterThrowingAdvice

它们都是MethodInterceptor的实现类:
image.png

链式调用通知方法

获取到了代理对象目标方法的拦截器链后,我们最后来关注这些拦截器是如何链式调用通知方法的。获取拦截器链并且拦截器链不为空时,CglibAopProxyintercept方法创建CglibMethodInvoation对象,并调用它的proceed方法:
image.png
查看CglibMethodInvocation源码:
image.png
查看父类ReflectiveMethodInvocationproceed方法源码:
image.png
清除之前打的所有断点,在该方法上第一行打个断点,重新以Debug方式启动程序:
image.png
程序第一次进入该方法时currentInterceptorIndex值为-1,this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex)取出拦截器链第一个拦截器ExposeInvocationInterceptor,方法最后调用该拦截器的invoke方法,点击Step into,进入ExposeInvocationInterceptorinvoke方法:
image.pngmi就是我们传入的ReflectiveMethodInvocation对象,程序执行到mi.proceed方法时,Step Into进入该方法:
image.png
可以看到,此时程序第二次执行ReflectiveMethodInvocationproceed方法,currentInterceptorIndex值为0,this.interceptorsAndDynamicMethodMatchers.get_(_++this.currentInterceptorIndex_)_取拦截器链第二个拦截器MethodBeforeInterceptor,方法最后调用该拦截器的invoke方法,Step Into进入该方法:
image.png
可以看到MethodBeforeInterceptorinvoke方法第一行调用通知方法before,此时控制台打印内容如下:

  1. onBefore: test()开始执行,参数:[aop]

接着又通过mi.proceed再次调用ReflectiveMethodInvocationproceed方法,Step Into进入该方法:
image.png
此时程序第三次执行ReflectiveMethodInvocationproceed方法,currentInterceptorIndex值为1,this.interceptorsAndDynamicMethodMatchers.get_(_++this.currentInterceptorIndex_)_取拦截器链第三个拦截器AspectJAfterAdvice,方法最后调用该拦截器的invoke方法,Step Into进入该方法:
image.png
可以看到AspectJAfterAdviceinvoke方法内通过mi.proceed再次调用ReflectiveMethodInvocationproceed方法,Step Into进入该方法:
image.png
此时程序第四次执行ReflectiveMethodInvocationproceed方法,currentInterceptorIndex的值为2,this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex)取出拦截器链第四个拦截器AfterReturningAdviceInterceptor,方法最后调用该拦截器的invoke方法,Step Into进入该方法:
image.png
可以看到AfterReturningAdviceInterceptorinvoke方法内通过mi.proceed再次调用ReflectiveMethodInvocationproceed方法,Step Into进入该方法:
image.png
此时程序第五次执行ReflectiveMethodInvocationproceed方法,currentInterceptorIndex值为3,this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex)取出拦截器链第五个拦截器AspectJAfterThrowingAdvice,方法最后调用该拦截器的invoke方法,Step Into进入该方法:
image.png
可以看到AspectJAfterThrowingAdviceinvoke方法内通过mi.proceed再次调用ReflectiveMethodInvocationproceed方法,Step Into进入该方法:
image.png
此时程序第六次执行ReflectiveMethodInvocationproceed方法,currentInterceptorIndex值为4,条件程序,所以执行invokeJoinPoint方法,该方法内部通过反射调用了目标方法,执行后,控制台打印内容如下:

  1. onBefore: test()开始执行,参数:[aop]
  2. TargetClass: test()被执行

随着invokeJoinpoint()方法执行结束返回出战,程序回到AspectJAfterThrowingAdviceinvoke方法:
image.png
this.advice.afterReturning执行afterReturning通知方法,控制台打印内容如下:

  1. onBefore: test()开始执行,参数:[aop]
  2. TargetClass: test()被执行
  3. onAfter: test()执行结束,参数:[aop]

AfterReturningAdviceInterceptorinvoke方法执行结束出栈,程序回到AspectJAfterAdviceinvoke方法:
image.png
AspectJAfterAdviceinvoke方法最终执行finally after逻辑,控制台打印内容如下:

  1. onBefore: test()开始执行,参数:[aop]
  2. TargetClass: test()被执行
  3. onAfter: test()执行结束,参数:[aop]
  4. afterReturning: test()执行返回,参数:[aop],返回值:newaop

AspectJAfterAdviceinvoke方法执行结束出栈,程序回到MethodBeforeAdviceInterceptorinvoke方法:
image.png
MethodBeforeAdviceInterceptorinvoke方法正常执行结束,出栈,程序回到ExposeInvocationInterceptorinvoke方法:
image.png
ExposeInvocationInterceptorinvoke方法执行结束出栈,程序回到CglibAopProxyintercept方法:
image.png
CglibAopProxyintercep执行完毕后,整个AOP的拦截器链调用也随之结束了。

下面用一张图总结拦截器链调用过程:
Spring-AOP.svg

最终总结

(1)生成代理对象
@EnableAspectJAutoProxy模块驱动注解用于开启AspectJ自动代理,这个注解使用@Import导入一个AspectJAutoProxyRegistrarAspectJ自动代理注册器,这个类的作用是向IOC容器中注册AnnotationAwareAspectJAutoProxyCreator组件。

AnnotationAwareAspectJAutoProxyCreator的父类AbstractAutoProxyCreator重写了InstantiationAwareBeanPostProcessorpostProcessBeforeInstantiation方法和BeanPostProcessorpostProcessAfterInitialization方法。自定义Bean的实例化前逻辑中包含五个核心步骤,主要目的是进行一些校验,如果Bean本身就是切面类,那么就不会被代理了;如果我们自定义了TargetClass,则返回代理后的Bean。自定义Bean的初始化后逻辑中,主要进行wrapIfNecessary方法,先通过getAdvicesAndAdvisors方法获取Bean的通知方法集合并且进行排序,如果集合不为空,则通过createProxy创建该Bean的代理对象,最终会调用DefaultAopProxyFactorycreateAopProxy方法,这个方法会判断使用CGLIB还是JDK动态代理。
(如果代理对象没有实现接口或者实现的都是空接口,则使用CGLIB动态代理;默认使用JDK动态代理)

(2)生成拦截器链
目标方法会被CglibAopProxyintercept方法拦截,方法里会通过getInterceptorsAndDynamicInterceptionAdvice方法获取目标对象的拦截器链,该方法中会创建目标方法的缓存key,首先从methodCache缓存中获取拦截器链,第一次调用时获取到的必然为空,那么则调用advisorChainFactorygetInterceptorsAndDynamicInterceptionAdvice方法封装拦截器链,并且将拦截器链存入缓存,此后调用直接从缓存中获取,提高AOP的性能。

『springboot2.4.0』(之前的版本后面四个拦截器顺序反转)最终生成的拦截器链的类型顺序:

  1. ExposeInvocationInterceptor(默认拦截器)
  2. MethodBeforeAdviceInterceptor(方法执行前拦截器)
  3. AspectJAfterAdvice(方法执行完成拦截器)
  4. AfterReturningAdviceInterceptor(方法执行成功拦截器)
  5. AspectJAfterThrowingAdvice(方法执行异常拦截器)

(3)链式调用通知
如果拦截器链为空,则直接通过反射执行目标方法;不为空则创建一个CglibMethodInvocation对象,它是ReflectiveMethodInvocation的子类,内部的proceed方法主要逻辑是调用父类的proceed方法,内部维护了一个索引currentInterceptorIndex,初始值为-1,一步步取出拦截器链中的拦截器,并执行invoke方法,invoke方法中会通过参数this继续调用ReflectiveMethodInvocationproceed方法实现链式调用。
对于拦截器,ExposeInterceptorInvocation直接调用proceedMethodBeforeAdviceInterceptor先执行before再执行proceedAspectJAfterAdvice先调用proceed再执行invokeAdviceMethodAfterReturningAdviceInterceptor先调用proceed再执行afterReturningAspectJAfterThrowingAdvice先调用proceed再执行invokeAdviceMethod,先链式调用然后方法出栈,最后回到CglibAopProxyintercept方法,执行完毕后,拦截器链调用随之结束。