【Spring】Spring5 AOP 源码分析

AOP原理

本质原理:为每个需要被增强的组件(带有切入点的组件)创建一个代理对象,在需要执行切入点方法时,调用代理对象的相应方法,并在其中按顺序切入通知方法。

AOP使用 @EnableAspectJAutoProxy注解通过@Import的方式向容器中添加一个AnnotationAwareAspectJAutoProxyCreator组件,该组件本质上是一个后置处理器,它会随着其他后置处理器一起注册到容器中(在普通bean注册之前)。在普通bean实例化前(此时还未实例化,普通的后置处理器在组件调用构造器之后执行),调用该组件的applyBeanPostProcessorsBeforeInstantiation()方法把带有Aspect相关的切面类添加到增强器集合中,在bean实例化后(此时才会执行普通的后置处理器内的方法),再调用applyBeanPostProcessorsAfterInstantiation()方法为带有切入点的组件(待增强的组件)创建一个代理对象(其内含有相应的增强器)。之后在执行该组件代理对象的切入点方法时,则使用CglibAopProxy.intercept()拦截该方法的执行,并在其中获取满足当前方法的所有拦截器链(由增强器包装而成),使用拦截器链的链式机制按顺序执行通知方法与业务代码。

AOP中两个非常重要的组件:后置处理器拦截器(增强器)

  • 后置处理器:拦截组件的创建,为其创建代理对象
  • 拦截器(增强器):在代理对象执行目标方法时进行拦截,切入相应的通知方法

AOP简易执行流程

注册阶段:

  • 配置类开启 @EnableAspectJAutoProxy 注解。
  • @EnableAspectJAutoProxy注解会注册 AnnotationAwareAspectJAutoProxyCreator 组件(通过@Import(AspectJAutoProxyRegistrar.class)的方式)。 AnnotationAwareAspectJAutoProxyCreator本质上是一个后置处理器(实现了相应接口)
  • 容器刷新( refresh() 方法栈中):
    • registerBeanPostProcessors():创建并注册所有的后置处理器,此时创建了AnnotationAwareAspectJAutoProxyCreator组件,在创建时会执行invokeAwareMethods()方法,回调地执行其实现的setBeanFactory()方法以获取容器中的BeanFactory并创建BeanFactoryAspectJAdvisorsBuilderAdapter对象。
    • finishBeanFactoryInitialization():创建并注册其他普通单实例组件(非后置处理器)。AnnotationAwareAspectJAutoProxyCreator拦截每个组件的创建。Before(在组件调用构造器实例化前调用:若拦截到的组件是切面类,则加入到增强器(advisor)集合中(之后被包装为拦截器);After(在组件实例化完毕后调用,此时其他普通后置处理器已经完成了相应操作):若拦截到的组件需要被增强(满足切入点表达式的条件),则为该组件创建一个代理对象(其内含有相应的增强器),之后执行业务组件的被增强的方法时就会执行该代理对象的相应方法。

执行阶段:

  • 代理对象准备执行目标方法(带有切入点的目标方法)时, CglibAopProxy.intercept() 会进行拦截,加入增强的通知方法:
    • 先遍历找到有效(符合目标方法)拦截器链chain(之前的增强器包装成拦截器)
    • 利用拦截器的链式机制依次进入每一个拦截器进行执行(每个拦截器都会执行相应的通知方法)
    • 通过不断回调CglibMethodInvocation.proceed()方法链式地调用下一个拦截器
    • 执行效果:前置通知 -> 目标方法 -> 正常返回通知或异常返回通知 -> 后置通知
  • 代理对象执行普通方法(不带有切入点的目标方法)时, CglibAopProxy.intercept() 进行拦截后,因找不到该方法匹配的增强器(因为普通方法没有被切入增强),则直接执行代理对象的普通方法。
  • 没有被增强的普通对象不被拦截。

@EnableAspectJAutoProxy

要开启AOP自动代理,配置类中需要添加@EnableAspectJAutoProxy。整个AOP就是从@EnableAspectJAutoProxy注解开始执行的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@EnableAspectJAutoProxy
@Configuration
public class SpringConfigAOP {
// 将业务逻辑类加入到容器中
@Bean
public MathCalculator calculator(){
return new MathCalculator();
}

// 切面类加入到容器中
@Bean
public LogsAspects logsAspects(){
return new LogsAspects();
}
}

@EnableAspectJAutoProxy注解:

image-20210630165506770

@Import(AspectJAutoProxyRegistrar.class)

@Import(AspectJAutoProxyRegistrar.class)表明@EnableAspectJAutoProxy注解会向容器中注册AspectJAutoProxyRegistrar类。

AspectJAutoProxyRegistrar类实现了ImportBeanDefinitionRegistrar接口的registerBeanDefinitions()方法:

image-20210630190714343

该方法使用BeanDefinitionRegistry类的对象registry给容器中注册了一个id名称为internalAutoProxyCreatorAnnotationAwareAspectJAutoProxyCreator组件(注解装配模式的AspectJ自动代理创建器)。注册定义部分的代码:

image-20210630192408003

总结@EnableAspectJAutoProxy注解会向容器中注册了一个AspectJAutoProxyRegistrar组件,该组件会向容器中注册一个AnnotationAwareAspectJAutoProxyCreator组件,即创建了一个自动代理创建器。AOP的思想都是通过该组件实现

AnnotationAwareAspectJAutoProxyCreator

AnnotationAwareAspectJAutoProxyCreator类实现了两个接口:

  • SmartInstantiationAwareBeanPostProcessor接口:一种特殊的后置处理器,在每个普通组件创建前后(不同于普通后置处理器是在组件创建完成、初始化前后)拦截并将该组件的代理对象注册到容器中,后续执行该组件的切入点方法时将调用代理对象的相应方法以切入通知方法。它实现的接口方法为postProcessBeforeInstantiation(),有区别于其他BeanPostProcessor里的postProcessBeforeInitialization()
  • BeanFactoryAware接口:在AnnotationAwareAspectJAutoProxyCreator组件被注册到容器中时(每个组件在创建时首先会执行invokeAwareMethods()方法,此时会回调BeanFactoryAware的接口方法),获取到容器中的组件创建工厂BeanFactory,并创建BeanFactoryAspectJAdvisorsBuilderAdapter(组件工厂通知构建器的适配器)对象用于后续为组件创建代理对象

image-20210630193143177

因此需要关心其实现的两个接口方法各有什么功能。

BeanFactoryAware接口的作用

作用:获取组件创建工厂BeanFactory

AnnotationAwareAspectJAutoProxyCreator的父类AspectJAwareAdvisorAutoProxyCreator(上图红色框所示)重写了BeanFactoryAware接口的setBeanFactory()方法AnnotationAwareAspectJAutoProxyCreator类本身并没有重写该方法),该方法内调用了initBeanFactory()方法(被AnnotationAwareAspectJAutoProxyCreator类重写)。

AnnotationAwareAspectJAutoProxyCreator组件被注册到容器中时,容器会执行invokeAwareMethods()方法,这是Aware接口的回调方法。因为AnnotationAwareAspectJAutoProxyCreator实现了Aware接口的setBeanFactory()方法,因此此时会执行其重写的setBeanFactory()方法获取bean创建工厂BeanFactory,并创建BeanFactoryAspectJAdvisorsBuilderAdapter(组件工厂通知构建器的适配器)对象用于后续为组件创建代理对象

image-20210704161324229

image-20210630220411754

SmartInstantiationAwareBeanPostProcessor接口的作用

作用:在每个普通组件创建前后进行拦截,并将满足切入点表达式的组件包装后的代理对象注册到容器中

SmartInstantiationAwareBeanPostProcessor接口的postProcessBeforeInstantiation()方法不同于其他BeanPostProcessor里的postProcessBeforeInitialization()。

AnnotationAwareAspectJAutoProxyCreator实现了SmartInstantiationAwareBeanPostProcessor接口,会使得其在所有的普通单实例bean创建前后能够进行拦截,调用postProcessBeforeInstantiation()方法注册每个增强器(切面类),调用postProcessorsAfterInitialization()方法将满足切入点表达式的组件包装后的代理对象注册到容器中。postProcessAfterInitialization()方法中调用wrapIfNecessary()为满足切入点表达式条件的组件包装出代理对象

image-20210703131501253

AOP详细执行流程

1. 传入配置类,创建IoC容器

image-20210630203107349

2. refresh():后续流程均在该方法内执行

补充IOC容器过程:注册配置类,调用refresh()方法刷新容器

image-20210630203127243

3. registerBeanPostProcessors():创建并注册所有后置处理器

refresh()方法内执行registerBeanPostProcessors()创建注册所有已定义的后置处理器,以在后续拦截普通bean的初始化。(步骤3和4中分析均为该方法内的执行逻辑)

image-20210630203203476

3.1 创建后置处理器实例化对象(只创建,还未注册)

3.1.1 在registerBeanPostProcessors()方法内:先获取IoC容器中所有已经定义了的需要实例化的BeanPostProcessor组件(此时还没创建对象实例)

image-20210630203357418

image-20210630202829082

此时的org.springframework.aop.config.internalAutoProxyCreator正是之前在@Import(AspectJAutoProxyRegistrar.class))中使用BeanDefinitionRegistry类给容器中添加定义的id名称为internalAutoProxyCreator的组件。(即之前BeanDefinitionRegistry定义了该后置处理器实现类,但还未创建实例化对象,步骤3.5处才创建了该组件)

image-20210630192408003

3.1.2 给容器添加其他BeanPostProcessor

image-20210630204433781

3.1.3 遍历3.1.1中取出的所有BeanPostProcessor,并根据其是否实现了Ordered接口进行分类

image-20210630213254910

3.1.4 优先创建实现了PriorityOrdered接口的BeanPostProcessor

image-20210630204659073

3.1.5 再创建实现了Ordered接口的BeanPostProcessor(以下分析均为3.5断点方法getBean()创建AnnotationAwareAspectJAutoProxyCreator对象的过程)

AnnotationAwareAspectJAutoProxyCreator类实现了Ordered接口,因此在这一步被创建(创建后再进行注册)

image-20210630204914536

以下分析如何创建id为internalAutoProxyCreatorAnnotationAwareAspectJAutoProxyCreator对象【本质为BeanPostProcessor对象 】?(注意,此步骤仅创建该对象,还未向容器中注册)

  1. 创建bean实例
  2. 调用populateBean(beanName, mbd, instanceWrapper) 为bean属性赋值
  3. 调用initializeBean(beanName, exposedObject, mbd)为bean初始化

image-20210629163559536

initializeBean()方法内部依次执行:

  • invokeAwareMethods()方法(绿色框):处理Aware接口的回调方法
  • applyBeanPostProcessorsBeforeInitialization()方法(红色框):调用后置处理器
  • invokeInitMethods()方法完成初始化(黄色框):执行自定义的初始化方法
  • applyBeanPostProcessorsAfterInitialization()方法(红色框):调用后置处理器

image-20210630214340913

调用invokeAwareMethods(beanName, bean)作用:执行Aware接口的回调方法。因为AnnotationAwareAspectJAutoProxyCreator类实现了BeanFactoryAware接口,因此在这里,执行了该组件的setBeanFactory()方法,用于获取bean创建工厂BeanFactory

image-20210630213635404

  1. 此时即调用了AnnotationAwareAspectJAutoProxyCreator类父类的setBeanFactory()方法(下图红色框),获取了bean创建工厂BeanFactory

image-20210630220411754

  1. 接着执行this.initBeanFactory((ConfigurableListableBeanFactory)beanFactory);(上图黄色框)创建了ReflectiveAspectJAdvisorFactory(反射的AspectJ增强器工厂)对象和并将其包装成BeanFactoryAspectJAdvisorsBuilderAdapter(组件工厂通知构建器的适配器)对象用于后续为组件创建代理对象

image-20210704164952614

3.1.6 最后再创建和注册没实现优先级接口的BeanPostProcessor

image-20210630204929418

总结:经过上述创建初始化等操作,此时3.5中getBean()方法执行完毕,获得了每个BeanPostProcessor(包括AnnotationAwareAspectJAutoProxyCreator)的实例化对象。

3.1步骤仅为 创建后置处理器的过程,此时的后置处理器还未注册到容器中

3.2 创建后的后置处理器注册到BeanFactory中

在创建出AnnotationAwareAspectJAutoProxyCreator的实例化对象后执行registerBeanPostProcessors()方法将AnnotationAwareAspectJAutoProxyCreator组件注册BeanFactory中:

image-20210630204914536

image-20210630221118378

3.1和3.2步骤即为创建和注册AnnotationAwareAspectJAutoProxyCreator组件的过程

4. finishBeanFactoryInitialization():注册普通组件

步骤3中已经注册了所有的BeanPostProcessor(黄色框),之后执行finishBeanFactoryInitialization()方法(红色框)注册所有非@Lazy修饰的单实例普通组件

image-20210701153743299

4.1 进入finishBeanFactoryInitialization()方法后,首先遍历获取容器中所有的beanNames,并依次执行以下方法创建bean对象。方法栈调用:

  • -> finishBeanFactoryInitialization(beanFactory)
  • -> beanFactory.preInstantiateSingletons()
  • -> getBean(beanName)
  • -> doGetBean()
  • -> getSingleton()
  • -> createBean()

image-20210701163050223

image-20210701163108692

image-20210701161459941

image-20210701161016809

image-20210701163847923

补充:在调用getSingleton()创建单实例bean之前,首先从缓存中查找当前bean是否存在,如果存在,说明这个bean之前已被创建过,可以直接使用,不再需要创建;否则再执行getSingleton()方法创建。只要创建好的bean都会被缓存起来。从缓存中查找bean是否存在:

image-20210701162202790

经过上述方法栈,在执行getBean(beanName)方法后创建bean的流程:

4.2 执行getSingleton(beanName)方法,从缓存中查找当前bean是否存在,如果存在,说明这个bean之前已被创建过,可以直接使用,不再需要创建;否则再执行getSingleton()方法创建。

4.3 进入createBean() 方法体:首先执行resolveBeforeInstantiation()方法(红色框,指在实例化前解析对象) ,该方法试图在此返回一个包装后的代理对象

  • 如果能返回代理对象(返回的bean != null)就使用(并且不再向下执行创建普通对象)
  • 如果不能返回代理对象(返回的bean == null)就向下继续执行doCreateBean()方法(黄色框)创建普通对象

image-20210701180818426

resolveBeforeInstantiation()方法体内,在实例化前先后执行前处理后处理

image-20210701181816332

5. applyBeanPostProcessorsBeforeInstantiation() 前处理:将切面类添加到增强器(通知方法)集合中其他作用?

进入applyBeanPostProcessorsBeforeInstantiation()方法,该方法调用getBeanPostProcessorCache()方法判断当前容器中是否存在实现了SmartInstantiationAwareBeanPostProcessor接口的组件。恰好AnnotationAwareAspectJAutoProxyCreator类实现了该接口,因此会调用该类的postProcessBeforeInstantiation()方法。(若不存在,则将不再执行后续代码,直接返回null,从而转去创建普通组件)

image-20210701182427290

image-20210701182344197

重点

  • BeanPostProcessor在普通bean对象创建完成之后,执行初始化方法前后调用
  • InstantiationAwareBeanPostProcessor在普通bean实例创建之前先进行拦截调用,尝试使用后置处理器将bean包装成代理对象

AnnotationAwareAspectJAutoProxyCreator实现了InstantiationAwareBeanPostProcessor接口,它会在任何bean实例创建之前(此时还没创建对象,也就还没执行普通BeanPostProcessor的处理器)先尝试执行postProcessBeforeInstantiation()返回对象的。

5.1若resolveBeforeInstantiation()方法无法返回代理对象(意味着容器中没有AnnotationAwareAspectJAutoProxyCreator组件,即不需要开启AOP,也自然不需要返回代理对象),则程序继续向下执行doCreateBean()方法。此时才真正地去创建一个普通单实例bean实例,该过程和3.5中流程一样

image-20210701171303958

5.2 若存在AnnotationAwareAspectJAutoProxyCreator组件,则将执行postProcessBeforeInstantiation()方法,该方法用于将所有切面类(带有通知方法的类)添加到增强器(通知方法)集合中。

每个组件都会进入该方法,但我们只关心和AOP相关的组件:自定义的MathCalculator(业务逻辑类)和LogAspect(切面类)。

image-20210703101045896

接上文:这一段作用?

image-20210704191747391

5.3 黄色框:判断当前advisedBeans.cotains(cacheKey)(保存了所有带有通知方法的bean,又被称为增强器)中是否已经包含了当前bean,若包含,则直接返回。

5.4 若不包含,则判断this.isInfrastructureClass(beanClass),即判断当前bean:

  • 是否是基础类型AdvicePointcutAdvisorAopInfrastructureBean接口的实现类。
  • 是否是切面类型(@Aspect注解修饰的类)

若符合,说明当前bean是切面类,则执行advisedBeans.put()方法将其添加到advisedBeans中(包含所有增强器),并向上层返回null。

5.5 判断this.shouldSkip(beanClass, beanName):判断是否需要跳过该bean的处理。

image-20210703104658589

image-20210703104753304

获取候选的增强器Advisors(切面里的通知方法),以ArrayList方式存储【List<Advisor> candidateAdvisors】。每一个封装的通知方法增强器是InstantiationModelAwarePointcutAdvisor类型,判断每一个增强器是否是AspectJPointcutAdvisor类型:若是,返回true;否则继续循环判断其他增强器,若都不是,返回false。

5.6 自定义的MathCalculator类经过5.4和5.5的判断均返回false,而LogAspect切面类因为被@Aspect注解修饰,所以会返回true,因此被添加到advisedBeans

总结AnnotationAwareAspectJAutoProxyCreator类的postProcessBeforeInstantiation()方法在组件实例化前调用,目的是将每个自定义的切面类添加到增强器集合中其他目的?

Before里不是特别确定

6. 经过前处理postProcessBeforeInstantiation()后,new一个MathCalculator对象

7. postProcesAfterInstantiation() 后处理:向容器中注册满足切入点表达式条件的代理对象

image-20210703131501253

7.1 调用this.wrapIfNecessary(bean, beanName, cacheKey)方法:如果需要的话进行包装。进入该方法后,调用this.getAdvicesAndAdvisorsForBean()以获取能切入到当前bean的增强器(通知方法)。将这些增强器存储为Object[] specificInterceptors拦截器数组。

image-20210704200120914

image-20210703132909220

该方法将遍历所有候选的增强器(通知方法),再找到能在当前bean使用的增强器(eligible,有资格的增强器),即找到哪些通知方法是需要切入到当前bean方法的。最后给有资格的增强器排序(排序是为了后续做切入时按照Before,After,AfterReturning等顺序执行)。

7.2 this.getAdvicesAndAdvisorsForBean()方法执行完成后获得了Object[] specificInterceptors,里面存有能切入到当前bean的所有增强器(通知方法)。如果当前specificInterceptors不为null,则说明当前bean有被增强,那么将当前bean保存到this.advisedBeans当中。

7.3 如果当前bean需要被增强,则执行this.createProxy()为其创建代理对象:

image-20210703153159704

接上段:

image-20210703154315455

该方法内执行流程:

  • 创建代理工厂ProxyFactory
  • 获取所有增强器(增强方法)并保存到ProxyFactory
  • 使用代理工厂创建代理对象proxyFactory.getProxy(classLoader),其中代理对象有两种,其由Spring自动决定:
    • JdkDynamicAopProxy(config):jdk动态代理
    • ObjenesisCglibAopProxy(config):cglib动态代理

proxyFactory.getProxy(classLoader)方法内执行了以下方法返回动态代理对象:

image-20210703153617812

总结:至此postProcesAfterInstantiation()方法中的this.wrapIfNecessary()方法执行完毕,其为容器中返回当前组件使用cglib增强了的代理对象(若实现了JDK接口,则返回JDK动态代理对象)。之后从容器中获取到的就是这个组件的代理对象,执行目标方法的时候,该代理对象就会额外执行通知方法的流程(除原本的业务代码外)。

该代理对象保存了许多详细信息(比如增强器、目标对象等),之后执行代理对象的方法时就会把通知方法一起执行:

image-20210703163430269

8. CglibAopProxy.intercept():拦截代理对象目标方法的执行

代理对象被注册到容器中后,当执行该bean被增强的方法时,AOP代理会执行CglibAopProxy.intercept()方法拦截目标方法的执行:

image-20210703163932927

8.1 获取拦截器链:该方法中执行ProxyFactory对象的getInterceptorsAndDynamicInterceptionAdvice()方法获取将要执行的目标方法拦截器链(拦截器集合,拦截器是由增强器包装后得到的,用于拦截每个目标方法的执行)。具体获得拦截器链的代码——进入该方法:

image-20210703164925461

image-20210703191531684

image-20210703193456012

接上段:

image-20210703191904882

  • 从配置类中获取所有的增强器(一个默认的增强器和其余自定义的增强器)
  • 创建List<Object> interceptorList 保存拦截器,长度为所有增强器的数量,包含一个默认的ExposeInvocationInterceptor拦截器
  • 遍历所有的增强器,将其转为拦截器:interceptors = registry.getInterceptors(advisor)

将增强器转为List<MethodInterceptor>的方式:

  • 如果传入的增强器advisor是MethodInterceptor,直接加入到集合中
  • 如果不是,则使用适配器AdvisorAdapter将增强器转为MethodInterceptor
  • 转换完成,返回每个增强器对应的拦截器MethodInterceptor

image-20210703192130240

AdvisorAdapter将增强器转为MethodInterceptor举例:

image-20210703192455597

总结:经过上述方法栈后,将每个增强器(通知方法)包装成了一个拦截器,返回了一个拦截器链(拦截器集合):

image-20210703193611280

8.2 得到拦截器链后,判断:

  • 如果没有拦截器链(说明当前目标方法没有被增强),直接执行目标方法
  • 如果有拦截器链(说明目标方法有被增强),把需要执行的目标对象、目标方法、拦截器链等所有信息传入一个CglibMethodInvocation对象,并调用其proceed()方法,从而执行带有通知方法的业务代码。

接上文获取拦截器链chain的代码:

image-20210703164633170

9. CglibMethodInvocation().proceed()方法解析:

进入CglibMethodInvocation().proceed()方法后:

  • 获取第一个拦截器;
  • 该拦截器执行invoke方法(将当前CglibMethodInvocation对象传入),该方法会再次地调用CglibMethodInvocation.proceed()方法;
  • currentInterceptorIndex记录当前拦截器的索引:从-1开始递增,每次执行procced(),索引自增一次,即再获取下一个拦截器;
  • 获取第二个拦截器后再次执行invoke方法,再次获取第三个拦截器;
  • 重复上述操作,直至获取到最后一个拦截器,执行完其通知方法(此时是第一次调用通知方法,其他拦截器的通知方法还未调用);
  • 执行完通知方法的拦截器将弹出方法栈,执行后续通知方法;

使用这种拦截器链的机制,按顺序调用其余的通知方法和目标方法。

下面按照执行顺序分析流程,假设当前bean对象共有四个自定义的拦截器(@Before@After@AfterReturnig@AfterThrowing)和一个默认的拦截器(ExposeInvocationInterceptor):

9.1 首次调用procced()方法,当前索引this.currentInterceptorIndex为-1,自加1后为0。

image-20210703224011722

this.interceptorsAndDynamicMethodMatchers中按顺序存储了所有拦截器(一个默认和四个自定义):

image-20210704115329357

首先取出第一个拦截器,调用其invoke方法,将CglibMethodInvocation对象作为参数传入:

image-20210703234254881

调用第一个默认的拦截器:ExposeInvocationInterceptorinvoke方法,在红色框中调用了CglibMethodInvocation.proceed()方法,从而获取了下一个拦截器@Before(此时finally代码块中的代码,还未执行,需要等到其余的方法栈全部执行完毕后最后执行)。

9.2 @Before:10.1中调用procced()获取到第二个拦截器MethodBeforeAdviceInterceptor:该拦截器首先执行advice.before(),即自定义的Before通知方法,再调用CglibMethodInvocation.proceed()方法获取下一个拦截器@After。注意此时Before通知已经执行。

image-20210704102922612

9.3 @After:获取到的下一个拦截器是AspectJAfterAdvice,该拦截器内将procced()方法包装在try代码块内。finally内的代码块为After后置通知方法,此时暂不调用,等待try内的mi.procced()方法栈执行完再调用。(因为@After的执行顺序在@AfterReturning@AfterThrowing之后,所以需要等到他们执行完后再调用)执行mi.procced()方法获取下一个拦截器@AfterReturing

image-20210704114113510

9.4 @AfterReturning:进入mi.procced()方法内获取了下一个拦截器AfterReturningAdviceInterceptor。该拦截器的invoke方法内再次调用mi.procced()方法获取下一个拦截器AfterThrowing。注意此处的代码并没有被try catch包裹,意味着后续方法栈出现异常此处无法继续向下正常执行advice.afterReturning()通知。

image-20210704114640043

9.5 @AfterThrowing:进入mi.procced()方法内获取了下一个拦截器AspectJAfterThrowing。此时再执行procced()方法时,因为该组件对应的拦截器已经全部遍历完,因此this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1判断成立,此时将执行目标对象的业务代码

image-20210704120009098

同时procced()方法包裹在try代码块中,若业务代码中出现异常,则将被后面的catch捕获,并执行invokeAdviceMethod()@AfterThrowing通知方法执行,同时抛出了一个异常ex,返回给上一层的@AfterReturing。上一层的@AfterReturing中并没有添加try catch代码块,因此若业务代码出现了异常,则将该异常抛给@AfterReturing后其无法继续执行后续的AfterReturing代码,反而将该异常继续向上抛给@After@After内有try,可以捕获)。也就说明@AfterReturing的通知不能在出现异常时执行,@AfterThrowing的通知不能在不出现异常时执行(因为异常通知方法在catch中,只有业务代码出现异常才能执行)

此时已经遍历完了所有的目标对象,执行目标对象的业务代码:

image-20210704120832349

执行完业务代码后,当前已经执行了@Before前置通知方法、目标对象业务代码,其余的通知方法还未执行。后续的执行顺序:

  • 如果业务代码内没有出现异常,则catch内的@AfterThrowing的通知不会执行,方法栈向上一层返回,返回到@AfterReturing,执行其@AfterReturing通知方法,执行后再返回到@After层执行@After通知方法。(此时都没有异常)
  • 如果业务代码内出现异常,则执行catch内的@AfterThrowing的通知,同时抛出异常ex,返回给上一层的@AfterReturing,而该层并没有try catch,因此不会执行@AfterReturing的通知,将此异常继续向上层抛出到@After

9.6 之后回到==@After层==,此处有try保证异常不会继续向上抛出,同时不论是否有异常抛出,都会执行invokeAdviceMethod()方法执行@After后置通知。因此说明@After通知不论是够有异常,都会在最后执行

image-20210704114113510

@After通知方法执行完后继续弹栈,此时所有的通知方法都执行完毕,顺序依次为:

  • 前置通知(@Before
  • 业务代码
  • 返回通知(@AfterReturning)/ 若有异常,此时执行异常通知(@AfterThrowing
  • 后置通知(@After
1
2
3
4
5
6
7
8
容器创建完成....

切入点div运行@Before .... 参数列表:{[1, 1]}
div方法执行...
切入点正常返回@AfterReturning....运行结果:{1}
切入点结束@After....

Process finished with exit code 0

补充:Spring4源码中拦截器调用的顺序与Spring5不同,是相反的顺序,但执行效果仍然相同:

image-20210704122728211

总体思想是链式地执行每个拦截器的invoke()方法,在合适的位置执行通知方法,并回调CglibMethodInvocation.procced()方法实现链式执行,直到所有的拦截器均执行完毕。

AOP原理总结

注册阶段

1、配置类开启 @EnableAspectJAutoProxy 注解。

2、@EnableAspectJAutoProxy注解会注册 AnnotationAwareAspectJAutoProxyCreator 组件(通过@Import(AspectJAutoProxyRegistrar.class)的方式)。 AnnotationAwareAspectJAutoProxyCreator本质上是一个后置处理器(实现了相应接口)

3、容器刷新( refresh() 方法栈中):

image-20210630203127243

image-20210704212659373

3.1、 registerBeanPostProcessors():创建并注册所有的后置处理器,此时创建了AnnotationAwareAspectJAutoProxyCreator组件,在创建时会执行invokeAwareMethods()方法,回调地执行其实现的setBeanFactory()方法以获取容器中的BeanFactory并创建BeanFactoryAspectJAdvisorsBuilderAdapter对象。

image-20210704212412161

3.2、 finishBeanFactoryInitialization():创建并注册其他普通单实例组件(非后置处理器)。

AnnotationAwareAspectJAutoProxyCreator拦截每个组件的创建,并判断该组件是否需要被代理:

  • 若需要被代理(符合切入点表达式),则执行下图红色框创建AOP代理对象,直接返回该代理对象,不再创建普通组件对象
  • 若不需要被代理,则执行下图黄色框创建普通组件对象

image-20210704212905374

resolveBeforeInstantiation()方法体内,在实例化普通组件前先后执行前处理后处理

image-20210701181816332

Before:若拦截到的组件是切面类,则加入到增强器(advisor)集合中(之后被包装为拦截器);

image-20210703101045896

After:若拦截到的组件需要被增强(满足切入点表达式的条件),则为该组件创建一个代理对象(cglib),之后执行业务组件的被增强的方法时就会执行该代理对象的相应方法。

image-20210703131501253

3.3、若当前组件没有含有切入点表达式(说明不需要被AOP代理),则创建普通组件(下图黄色框):

image-20210701180818426

执行阶段

代理对象准备执行目标方法(带有切入点的目标方法)时, CglibAopProxy.intercept() 会进行拦截,加入增强的通知方法:

1、 先遍历找到有效(符合目标方法)拦截器链chain(之前的增强器包装成拦截器)

image-20210703163932927

判断拦截器链是否为null,若为null,说明当前方法没有被增强,则直接执行目标方法:

image-20210703164633170

2、若有被增强,则利用拦截器的链式机制依次进入每一个拦截器进行执行(每个拦截器都会执行相应的通知方法)

image-20210703224011722

3、通过不断回调CglibMethodInvocation.proceed()方法链式地调用下一个拦截器

4、执行效果:前置通知 -> 目标方法 -> 正常返回通知或异常返回通知 -> 后置通知

代理对象执行普通方法(不带有切入点的目标方法)时, CglibAopProxy.intercept() 进行拦截后,因找不到该方法匹配的增强器(因为普通方法没有被切入增强),拦截器链为null,则直接执行代理对象的普通方法。

没有被增强的普通对象不被拦截。