Spring AspectJ相关aop注解拦截方法的执行先后顺序

811 阅读14分钟

前言

Spring Aop是Spring框架中一个重要模块,通过Spring Aop,我们可以很方便的在代码里完成方法级别切入逻辑。

例如:

 @Aspect
 @Component
 public class MyAop {
 ​
     @Pointcut("execution(* com.example.demo.aop..sayHello(..))")
     public void pointCut() {
     }
 ​
     @Before("pointCut()")
     public void method1() {
         System.out.println("@Before...");
     }
 }

如上代码,Spring和AspectJ相关注解,共同完成了的切入逻辑,这里插句题外话,其实Spring起初是想自己整一套Aop类库的,可是整出来的东西并不好用,所以使用了市面上优秀的AspectJ Aop类库。

经常使用到的AspectJ相关注解,除了上面示例代码中的@Before之外,还有@Around、@After、@AfterReturning、@AfterThrowing等注解。

这几个注解修饰的方法的调用时机以及执行顺序本该是一件非常明确的事情,但是因为Spring离奇操作,不同版本下,@After、@AfterReturning、@AfterThrowing这三个注解修饰的方法的执行顺序有些略微不同。

这块知识很容易对产生混乱,因此,后面就通过解析源码的方式,记录一下它们真正的调用时机以及执行顺序。

先说结论

代码示例:

 @Aspect
 @Component
 public class MyAop {
 ​
     @Pointcut("execution(* com.example.demo.aop..sayHello(..))")
     public void pointCut() {
     }
 ​
     @Around("pointCut()")
     public Object method1(ProceedingJoinPoint joinPoint) throws Throwable {
         System.out.println("@Around... 1");
         Object result = joinPoint.proceed();
         System.out.println("@Around... 2");
         return result;
     }
 ​
     @Before("pointCut()")
     public void method2() {
         System.out.println("@Before...");
     }
 ​
     @After("pointCut()")
     public void method3() {
         System.out.println("@After...");
     }
 ​
     @AfterReturning(value = "pointCut()", returning = "retValue")
     public void method4(Object retValue) {
         System.out.println("@AfterReturning...");
     }
 ​
     @AfterThrowing(value = "pointCut()", throwing = "exception")
     public void method5(Exception exception) {
         System.out.println("@AfterThrowing...");
     }
 }
 ​
 @Component
 public class Man {
 ​
     private String name = "Tom";
 ​
     public void sayHello() {
         System.out.println("hello, i am " + name);
     }
 ​
 }
Spring5.2.7版本之后
 System.out.println("@Around... 1");
 Object result = joinPoint.proceed();
 System.out.println("@Around... 2");
 ​
 ​
 // joinPoint.proceed()实际上就是执行下面的代码
 System.out.println("@Before...");
 try {
   try {
     // 执行目标方法
     System.out.println("hello, i am " + name);
   } catch (Throwable ex) {
     System.out.println("@AfterThrowing...");
     throw ex;
   }
   System.out.println("@AfterReturning...");
 } finally {
   System.out.println("@After...");
 } 
Spring5.2.7版本之前

5.2.7版本之前,与上面的区别就是@After比@AfterReturning/@AfterThrowing注解修饰的切入方法先执行

 System.out.println("@Around... 1");
 Object result = joinPoint.proceed();
 System.out.println("@Around... 2");
 ​
 ​
 // joinPoint.proceed()实际上就是执行下面的代码
 System.out.println("@Before...");
 try {
     try {
       // 执行目标方法
       System.out.println("hello, i am " + name);
     } finally {
       System.out.println("@After...");
     } 
     System.out.println("@AfterReturning...");
   } catch (Throwable ex) {
     System.out.println("@AfterThrowing...");
     throw ex;
   }
 ​

再看源码

源码版本基于Spring 5.3.16(5.2.7版本之后),这里以单例且需要被代理的Bean的生命周期为主线,介绍Spring Aop中的几个重要过程。

1、实例化bean之前,提前创建容器中存在的所有Advisors

Advisor是Spring提供的一个接口,可以翻译为增强器

一般注册到Spring中的Advisor有两种,一种是直接实现了Advisor接口的Bean,一种是解析使用了@Aspect注解的Bean,得到的Advisor对象(比较常见,也是重点研究对象)。

自定义的@Aspect Bean被称为一个切面,在这个Bean class中,可以使用AspectJ的@Before、@Around等注解修饰在某个方法上,被这些注解修饰的每个方法,都会被解析出一个Advisor对象放到容器中。所以,一个切面(@Aspect Bean)可能包含多个增强器(Advisor)。

这一步主要是找出这两种Advisor,并且创建出来,放到容器中。

 // 代码位置:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])
 ​
 ​
 @Override
 protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
     throws BeanCreationException {
   // ...不重要代码省略
 ​
   try {
     // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
     // "能不能给个机会,我想直接返回一个代理对象",但是这一步的操作不仅仅如此,还有很重要的一点,实例化bean之前,提前创建容器中存在的所有Advisors。
     Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
     if (bean != null) {
       return bean;
     }
   }
   catch (Throwable ex) {
     throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
         "BeanPostProcessor before instantiation of bean failed", ex);
   }
 ​
   try {
     // 实例化、初始化等一系列bean的生命周期就是这里完成的
     Object beanInstance = doCreateBean(beanName, mbdToUse, args);
     if (logger.isTraceEnabled()) {
       logger.trace("Finished creating instance of bean '" + beanName + "'");
     }
     return beanInstance;
   }
   
   // ...不重要代码省略
 }
 ​
 protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
   Object bean = null;
   if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
     // Make sure bean class is actually resolved at this point.
     if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
       Class<?> targetType = determineTargetType(beanName, mbd);
       if (targetType != null) {
         // 进到这里
         bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
         if (bean != null) {
           bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
         }
       }
     }
     mbd.beforeInstantiationResolved = (bean != null);
   }
   return bean;
 }
 ​
 protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
   for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
     // 这里遍历到AnnotationAwareAspectJAutoProxyCreator执行postProcessBeforeInstantiation方法
     Object result = bp.postProcessBeforeInstantiation(beanClass, beanName);
     if (result != null) {
       return result;
     }
   }
   return null;
 }

获取到AnnotationAwareAspectJAutoProxyCreator对象执行postProcessBeforeInstantiation方法,实际上是执行父类AbstractAutoProxyCreator的postProcessBeforeInstantiation方法。

 // 代码位置:org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInstantiation
 ​
 public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
   Object cacheKey = getCacheKey(beanClass, beanName);
 ​
   if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
     if (this.advisedBeans.containsKey(cacheKey)) {
       return null;
     }
     // shouldSkip方法完成了Advisors的创建
     if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
       this.advisedBeans.put(cacheKey, Boolean.FALSE);
       return null;
     }
   }
 ​
   // ...不重要代码省略
 }
 ​
 @Override
 protected boolean shouldSkip(Class<?> beanClass, String beanName) {
   // TODO: Consider optimization by caching the list of the aspect names
   // 查找容器中所有的Advisors,Advisor可能是一个实现了Advisor接口的bean,又或者是@Aspect注解修饰的bean class中被@Before、@After等注解修饰的方法解析出的Advisor(每个方法对应一个Advisor)
   List<Advisor> candidateAdvisors = findCandidateAdvisors();
   // ...
 }
 ​
 @Override
 protected List<Advisor> findCandidateAdvisors() {
   // Add all the Spring advisors found according to superclass rules.
   // 查找容器中实现了Advisor接口的bean,创建并返回
   List<Advisor> advisors = super.findCandidateAdvisors();
   // Build Advisors for all AspectJ aspects in the bean factory.
   if (this.aspectJAdvisorsBuilder != null) {
     // 创建Aspect Bean中被@Before、@After等注解修饰的方法解析出的Advisor
     advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
   }
   return advisors;
 }
 ​
 public List<Advisor> buildAspectJAdvisors() {
   // ...不重要代码省略
 ​
   // 获取容器中Object类型的所有beanNames,那就等同于获取容器中的所有beanNames     
   String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
       this.beanFactory, Object.class, true, false);
   for (String beanName : beanNames) {
     // ...不重要代码省略
 ​
     // 获取beanName对应的类型
     Class<?> beanType = this.beanFactory.getType(beanName, false);
     if (beanType == null) {
       continue;
     }
     // 如果beanType被@Aspect注解修饰,是一个Aspect Bean,也就是我们定义的切面类,就解析它了
     if (this.advisorFactory.isAspect(beanType)) {
       aspectNames.add(beanName);
       AspectMetadata amd = new AspectMetadata(beanType, beanName);
       if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
         MetadataAwareAspectInstanceFactory factory =
             new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
         // 解析Aspect Bean中的所有Advisor返回
         List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
 ​
         // ...不重要代码省略
       }
       // ...不重要代码省略
     }
   }
   // ...不重要代码省略
 }

上面这段代码的逻辑,已经能看到Advisors来源于两部分,一部分来自于容器中实现了Advisor接口的bean,一部分就是解析Aspect Bean得到的。前者不关注,这里只关注后者是如何解析得到的。

 // 代码位置:org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisors
 ​
 @Override
 public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
   // ...不重要代码省略
 ​
   List<Advisor> advisors = new ArrayList<>();
   // aspectClass就是Aspect Bean对应的class,这里获取被AspectJ相关注解修饰的方法,注意,不同注解修饰的方法返回的顺序很重要
   // 这里返回的顺序在5.2.7版本后,将直接决定,后续方法切入时,拦截器链的执行顺序。
   // 因为本方法内还有重要的待分析点,所以临时把对getAdvisorMethods方法的解析标记为①,表示一条执行链路
   for (Method method : getAdvisorMethods(aspectClass)) {
     // Prior to Spring Framework 5.2.7, advisors.size() was supplied as the declarationOrderInAspect
     // to getAdvisor(...) to represent the "current position" in the declared methods list.
     // However, since Java 7 the "current position" is not valid since the JDK no longer
     // returns declared methods in the order in which they are declared in the source code.
     // Thus, we now hard code the declarationOrderInAspect to 0 for all advice methods
     // discovered via reflection in order to support reliable advice ordering across JVM launches.
     // Specifically, a value of 0 aligns with the default value used in
     // AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor).
     // 这个分析点标记为②,看完①所有流程后,可以返回来看
     // ①对获取到的方法进行了排序,这里依次解析每个方法,创建一个Advisor对象返回加入到集合中。
     // 注意这里第三个参数0,这里就是为什么spring在5.2.7版本之后,拦截器执行的先后顺序不同的关键,先把问题留在这里
     Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
     if (advisor != null) {
       advisors.add(advisor);
     }
   }
   // ...不重要代码省略
   return advisors;
 }
 ​
 ①
 private List<Method> getAdvisorMethods(Class<?> aspectClass) {
   List<Method> methods = new ArrayList<>();
   // 过滤掉aspectClass中的桥接方法、合成方法、Object类中的相关方法以及被注解@Pointcut修饰的方法,返回剩下的所有方法
   ReflectionUtils.doWithMethods(aspectClass, methods::add, adviceMethodFilter);
   if (methods.size() > 1) {
     // 对方法排序。这里的排序规则很重要,所以要看一下这个comparator的排序规则是怎么定义的
     // 经过adviceMethodComparator排序的method,返回的顺序是按照@Around、@Before、@After、@AfterReturning、@AfterThrowing排序的
     methods.sort(adviceMethodComparator);
   }
   return methods;
 }
 ​
 ①
 private static final Comparator<Method> adviceMethodComparator;
 static {
   // Note: although @After is ordered before @AfterReturning and @AfterThrowing,
   // an @After advice method will actually be invoked after @AfterReturning and
   // @AfterThrowing methods due to the fact that AspectJAfterAdvice.invoke(MethodInvocation)
   // invokes proceed() in a `try` block and only invokes the @After advice method
   // in a corresponding `finally` block.
   // 对于传入的method,先获取方法上注解,根据注解被定义在InstanceComparator的顺序进行排序
   Comparator<Method> adviceKindComparator = new ConvertingComparator<>(
       // 按照元素被定义的顺序排序
       new InstanceComparator<>(
           Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
       (Converter<Method, Annotation>) method -> {
         // 获取方法上存在的Pointcut、Around、Before、After、AfterReturning、AfterThrowing类型的注解
         AspectJAnnotation<?> ann = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
         return (ann != null ? ann.getAnnotation() : null);
       });
   Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName);
   // 如果不同方法上被修饰的注解相同,再根据方法名排序
   adviceMethodComparator = adviceKindComparator.thenComparing(methodNameComparator);
 }
 ​
 ②
 @Override
 @Nullable
 public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
     int declarationOrderInAspect, String aspectName) {
   // 一些简单的校验逻辑,比如aspectClass的父类如果有@Aspect注解,那么父类一定得是abstract的,不然就报错;再比如aspectClass必须要含有@Aspect注解,否则也会报错
   validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
 ​
   // 查找指定方法上AspectJ的相关切面注解,并解析注解的pointcut或者value属性值,例如解析@Around(value = "myPointcut()"),value属性值为"myPointcut()",包装成AspectJAnnotation
   AspectJExpressionPointcut expressionPointcut = getPointcut(
       candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
   if (expressionPointcut == null) {
     return null;
   }
 ​
   // 实例化Advisor
   return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
       this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
 }
 ​
 ②
 public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
       Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
       MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
 ​
   // ...不重要代码省略
   // Spring5.2.7版本后,declarationOrder传入的都是0
   this.declarationOrder = declarationOrder;
   // ...不重要代码省略
   else {
     // A singleton aspect.
     this.pointcut = this.declaredPointcut;
     this.lazy = false;
 ​
     // 按照方法上不同的注解类型,创建不同的Advice,例如@Before对应的是AspectJMethodBeforeAdvice对象,@Around对应的是AspectJAroundAdvice对象
     this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
   }
 }

上面这段代码,Spring主要是对Aspect Bean做了解析,解析被Around、Before、After、AfterReturning、AfterThrowing注解修饰的方法,每个方法创建一个Advisor对象,每个Advisor对象中包含一个Advice对象(称为"通知")。

在解析Aspect Bean过程中,有个地方非常重要,那就是创建Advisor的顺序,Spring按照Around、Before、After、AfterReturning、AfterThrowing这个顺序一个接一个创建出Advisor,最终放到一个List中返回。

此外,上面代码中,还提到了遗留了一个问题,创建Advisor时,传入构造函数中的declarationOrder属性值,有什么用?不同版本有什么区别?后面会一点点解答。

2、bean的初始化方法执行后,执行afterInitialization方法时,判断是否需要创建代理对象

bean先被实例化,然后完成属性填充,在执行初始化方法(指定的init方法或者实现了InitializingBean重写的方法)之后,执行后置处理器的postProcessAfterInitialization方法过程中,会判断当前bean是否需要创建一个代理对象,如果需要,那么获取容器中的所有Advisors,根据Advisor的切点表达式找到与当前bean匹配的所有Advisors返回,如果返回的Advisors不为空,就为当前bean创建一个代理对象。

 // 代码位置:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
 ​
 protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
       throws BeanCreationException {
 ​
   // Instantiate the bean.
   BeanWrapper instanceWrapper = null;
   if (mbd.isSingleton()) {
     instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
   }
   if (instanceWrapper == null) {
     // 实例化bean
     instanceWrapper = createBeanInstance(beanName, mbd, args);
   }
   Object bean = instanceWrapper.getWrappedInstance();
   // ...不重要代码省略
 ​
   // Initialize the bean instance.
   Object exposedObject = bean;
   try {
     // bean的属性填充
     populateBean(beanName, mbd, instanceWrapper);
     // 初始化bean。这个过程包含beforeInitialization、init、afterInitialization三个过程
     exposedObject = initializeBean(beanName, exposedObject, mbd);
   }
   // ...不重要代码省略
   return exposedObject;
 }
 ​
 @Override
 public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
     throws BeansException {
   Object result = existingBean;
   for (BeanPostProcessor processor : getBeanPostProcessors()) {
     // 进入AbstractAutoProxyCreator#postProcessAfterInitialization
     Object current = processor.postProcessAfterInitialization(result, beanName);
     if (current == null) {
       return result;
     }
     result = current;
   }
   return result;
 }
 ​
 @Override
 public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
   if (bean != null) {
     Object cacheKey = getCacheKey(bean.getClass(), beanName);
     if (this.earlyProxyReferences.remove(cacheKey) != bean) {
       // 这里有个earlyProxyReferences需要说明一下,Spring用来解决循环依赖问题引入了三级缓存,这里是用来存放在循环依赖中执行过一次wrapIfNecessary方法的bean,防止为代理对象重复创建代理对象。
       // 循环引用的东西不在这里说,这里主要关注创建代理对象的wrapIfNecessary方法即可。
       return wrapIfNecessary(bean, beanName, cacheKey);
     }
   }
   return bean;
 }
 ​
 protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
   // ...不重要代码省略
 ​
   // shouldSkip方法在上面第1步已经走过一遍了,所以,这里其实就是走一下缓存
   if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
     this.advisedBeans.put(cacheKey, Boolean.FALSE);
     return bean;
   }
 ​
   // Create proxy if we have advice.
   // 根据每个Advisor的切点表达式从容器中找到所有符合匹配bean的Advisors返回。
   // 这里很重要,因为这里返回的顺序,就直接决定了这个代理对象后续执行目标方法时,aop拦截链的执行顺序
   Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
   if (specificInterceptors != DO_NOT_PROXY) {
     this.advisedBeans.put(cacheKey, Boolean.TRUE);
     // 选个策略(jdk or cglib)创建代理对象吧
     Object proxy = createProxy(
         bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
     this.proxyTypes.put(cacheKey, proxy.getClass());
     return proxy;
   }
 ​
   this.advisedBeans.put(cacheKey, Boolean.FALSE);
   return bean;
 }

上面这段代码,从bean的生命周期出发,一直到AbstractAutoProxyCreator#wrapIfNecessary方法中,获取当前bean匹配的所有Advisors返回,返回的顺序很重要,因为只有在这一步才会进行Advisors排序,后续逻辑对Advisors不再排序,这一步获取到Advisors的顺序是怎样的,代理对象后续执行目标方法前,执行的拦截器链顺序就是怎样的。

下面分析一下这个getAdvicesAndAdvisorsForBean方法

 // 代码位置:org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean
 ​
 @Override
 @Nullable
 protected Object[] getAdvicesAndAdvisorsForBean(
     Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
   
   // 查找"有资格"的Advisors,即能与beanClass匹配的Advisors
   List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
   if (advisors.isEmpty()) {
     return DO_NOT_PROXY;
   }
   return advisors.toArray();
 }
 ​
 protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
   // 获取容器中所有的Advisors,上面第1步已经缓存在容器中了,所以这里就是从缓存中取数据
   List<Advisor> candidateAdvisors = findCandidateAdvisors();
   // 遍历所有的Advisors,根据每个Advisor中的切点表达式,调用AspectJ类库相关api,判断beanClass中是否存在某个方法与切点表达式匹配,如果存在,就返回这个Advisor。
   List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
   // 在列表头部,加一个扩展的Advisor,用来后续执行目标方法前,执行aop拦截链,暴露MethodInvocation对象
   extendAdvisors(eligibleAdvisors);
   if (!eligibleAdvisors.isEmpty()) {
     // Advisors排序
     eligibleAdvisors = sortAdvisors(eligibleAdvisors);
   }
   return eligibleAdvisors;
 }
 ​
 @Override
 protected List<Advisor> sortAdvisors(List<Advisor> advisors) {
   List<PartiallyComparableAdvisorHolder> partiallyComparableAdvisors = new ArrayList<>(advisors.size());
   for (Advisor advisor : advisors) {
     // 给每个Advisor包装成一个PartiallyComparableAdvisorHolder对象,指定一个默认优先级比较器
     // 这里我要吐槽一下:这个PartiallyComparableAdvisorHolder是PartialComparable类型的,PartialComparable是AspectJ类库的一个接口,Spring为了能用上AspectJ的比较对象的方法,先包装了成了这个对象,后面比较完成之后又一个个从这个包装对象中取出来Advisor返回。一开始,我以为spring这样做,可能是觉得AspectJ的这个比较算法比较牛x,然而当我看过之后,发现这个算法复杂度竟然是n²,离谱!!!
     partiallyComparableAdvisors.add(
         new PartiallyComparableAdvisorHolder(advisor, DEFAULT_PRECEDENCE_COMPARATOR));
   }
   // 排序,排序算法是AspectJ提供的,但是排序规则是spring定义的,在DEFAULT_PRECEDENCE_COMPARATOR对象中,这里其实只需要关注排序规则就行了。
   List<PartiallyComparableAdvisorHolder> sorted = PartialOrder.sort(partiallyComparableAdvisors);
   if (sorted != null) {
     List<Advisor> result = new ArrayList<>(advisors.size());
     for (PartiallyComparableAdvisorHolder pcAdvisor : sorted) {
       // 从包装对象中取出Advisor
       result.add(pcAdvisor.getAdvisor());
     }
     return result;
   }
   else {
     return super.sortAdvisors(advisors);
   }
 }
 ​
 // 排序规则
 private static final Comparator<Advisor> DEFAULT_PRECEDENCE_COMPARATOR = new AspectJPrecedenceComparator();
 ​
 class AspectJPrecedenceComparator implements Comparator<Advisor> {
   private final Comparator<? super Advisor> advisorComparator;
   
   public AspectJPrecedenceComparator() {
     this.advisorComparator = AnnotationAwareOrderComparator.INSTANCE;
   }
   
   /**
   * 这个就是最终的排序规则,这个排序规则的具体代码就不贴了,方法调来调去的一堆逻辑,这里简单表述一下排序规则。
   */
   @Override
   public int compare(Advisor o1, Advisor o2) {
     // AnnotationAwareOrderComparator这个比较器的比较规则如下:首先PriorityOrdered类型对象的优先级更高,然后再比较两个对象获取的order数值,数值越小,优先性越高。
     // order数值从哪来?如果Advisor实现了接口Ordered,那么就会调用advisor.getOrder()方法获取order值,advisor的真实类型是InstantiationModelAwarePointcutAdvisorImpl(比较常见),那么实际上order数值来源于此Advisor对应的那个bean class,比如我们定义@Aspect类时,同时在类上指定@Order注解,或者让bean class实现Ordered接口,重写getOrder方法,所以绕来绕去,这里就是比较Advisor所在的Aspect Bean class的优先级。
     int advisorPrecedence = this.advisorComparator.compare(o1, o2);
     if (advisorPrecedence == SAME_PRECEDENCE && declaredInSameAspect(o1, o2)) {
       // 如果按照上面的比较器比较两个Advisor,返回结果为0,并且这两个Advisor有相同的AspectName名称,那么就尝试比较一下Advisor中的Advice的优先级以及Advisor中属性declarationOrder的大小,不过在spring5.2.7之后,进入到这个方法实际上是没啥意义的,因为返回的还是0,比不出优先顺序。
       advisorPrecedence = comparePrecedenceWithinAspect(o1, o2);
     }
     return advisorPrecedence;
   }
   
   // ...
 }
 ​
 ​
 private int comparePrecedenceWithinAspect(Advisor advisor1, Advisor advisor2) {
   // 调用Advisor中包装的Advice对象的isAfterAdvice()方法返回。对于@After、@AfterReturning、@AfterThrowing这三个注解对应的Advice,都会返回true
   boolean oneOrOtherIsAfterAdvice =
       (AspectJAopUtils.isAfterAdvice(advisor1) || AspectJAopUtils.isAfterAdvice(advisor2));
   // 这里就是前面遗留下来的declarationOrder属性值问题,获取advisor的属性declarationOrder值,然后相减。
   // 从5.2.7版本后,构造advisor的传参declarationOrder都是0,所以这里相减也是0,所以当前方法也比不出优先顺序。
   int adviceDeclarationOrderDelta = getAspectDeclarationOrder(advisor1) - getAspectDeclarationOrder(advisor2);
 ​
   if (oneOrOtherIsAfterAdvice) {
     // the advice declared last has higher precedence
     if (adviceDeclarationOrderDelta < 0) {
       // advice1 was declared before advice2
       // so advice1 has lower precedence
       return LOWER_PRECEDENCE;
     }
     else if (adviceDeclarationOrderDelta == 0) {
       return SAME_PRECEDENCE;
     }
     else {
       return HIGHER_PRECEDENCE;
     }
   }
   else {
     // the advice declared first has higher precedence
     if (adviceDeclarationOrderDelta < 0) {
       // advice1 was declared before advice2
       // so advice1 has higher precedence
       return HIGHER_PRECEDENCE;
     }
     else if (adviceDeclarationOrderDelta == 0) {
       return SAME_PRECEDENCE;
     }
     else {
       return LOWER_PRECEDENCE;
     }
   }
 }

上面这段代码中,获取了与当前bean匹配的所有Advisors,并且对Advisors进行了排序,排序的详细规则如下:

  1. 先按照Advisor所在的Aspect Bean的顺序排序Advisor,Aspect Bean可以通过实现PriorityOrdered、Ordered接口,以及使用@Order注解来指定优先顺序,order数值越大优先级越低。
  2. 同一个Aspect Bean中的Advisors排序规则主要依靠于创建Advisor对象时declarationOrder的字段值,但是在5.2.7版本后,这个值都是0,没有比较意义。

因此,从这里来看,spring5.2.7之后,同一个Aspect Bean中的Advisor的优先级顺序就是上面第1步按照Around、Before、After、AfterReturning、AfterThrowing这个顺序创建Advisor的顺序。

本着用新不用旧的态度,5.2.7版本之前是什么样的?这里还是先不说吧,放在后面贴一下代码。

3、目标对象执行目标方法前,aop拦截链执行过程

上面第2步,只是告诉我们一个要创建代理对象的bean,匹配上的Advisors返回顺序是怎样的,并且这个顺序就是后续为每个Advisor中的Advice创建拦截器,组成拦截器链的顺序。

既然排序规则有了,但是调用细节还是未知,比如@Around分为执行目标方法前上半段和执行目标方法后下半段,什么时候执行上半段、什么时候执行下半段?明明@After排在@AfterReturning/@AfterThrowing这两者的前面,为什么会在@AfterReturning/@AfterThrowing之后执行?等等问题。

这里就通过源码的方式,看一下这个过程,以jdk动态代理为例吧(cglib的拦截器链执行过程和jdk是通用的,只不过cglib中东西比较多,没有jdk好说明过程)

 // 代码位置:JdkDynamicAopProxy
 ​
 @Override
 public Object getProxy(@Nullable ClassLoader classLoader) {
   if (logger.isTraceEnabled()) {
     logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
   }
   // jdk动态代理创建很简单,第三个参数是实现了InvocationHandler接口的对象,传入了当前对象。
   // 那么执行目标对象每个方法前的回调逻辑就在本类中重写的invoke(Object proxy, Method method, Object[] args)方法中了
   return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);
 }
 ​
 @Nullable
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   Object oldProxy = null;
   boolean setProxyContext = false;
 ​
   TargetSource targetSource = this.advised.targetSource;
   Object target = null;
 ​
   try {
     // ...
     Object retVal;
 ​
     // ...
     target = targetSource.getTarget();
     Class<?> targetClass = (target != null ? target.getClass() : null);
 ​
     // Get the interception chain for this method.
     // 获取拦截器链,就是将advised中的每一个Advisor中的Advice对象,包装成Interceptor对象返回
     // Advice有可能本身就是一个Interceptor,就不用包装,比如AspectJAroundAdvice;但是@Before对应的AspectJMethodBeforeAdvice对象就需要包装成MethodBeforeAdviceInterceptor返回,这里不详细看了。
     List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
 ​
     // Check whether we have any advice. If we don't, we can fallback on direct
     // reflective invocation of the target, and avoid creating a MethodInvocation.
     if (chain.isEmpty()) {
       // We can skip creating a MethodInvocation: just invoke the target directly
       // Note that the final invoker must be an InvokerInterceptor so we know it does
       // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
       Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
       // 拦截器链为空,是个普通非代理方法,直接反射执行吧
       retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
     }
     else {
       // We need to create a method invocation...
       MethodInvocation invocation =
           new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
       // Proceed to the joinpoint through the interceptor chain.
       // 拦截器链不为空,创建MethodInvocation对象,开始执行拦截器链
       retVal = invocation.proceed();
     }
 ​
     // ...
     return retVal;
   }
   // ...
 }

拦截器链的执行过程细节,重点在于invocation.proceed()

 // 代码位置:org.springframework.aop.framework.ReflectiveMethodInvocation#proceed
 ​
 @Override
 @Nullable
 public Object proceed() throws Throwable {
   // We start with an index of -1 and increment early.
   if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
     // 执行真目标对象真正的方法
     // 什么时候执行?等到currentInterceptorIndex等于拦截器链中最后一个的拦截器下标时,也就是执行过最后一个拦截器之后
     return invokeJoinpoint();
   }
 ​
   Object interceptorOrInterceptionAdvice =
       this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
   // ...
   else {
     // It's an interceptor, so we just invoke it: The pointcut will have
     // been evaluated statically before this object was constructed.
     // 调用拦截器的invoke方法,执行拦截器拦截逻辑
     return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
   }
 }

在proceed()方法中,可以看到拦截器链是按照拦截器的顺序,依次执行拦截逻辑的,这里以上面同时包含@Around、@Before、@After、@AfterReturning、@AfterThrowing注解的代码为例,走一遍拦截器的执行流程。

这几个注解分别对应的拦截器是AspectJAroundAdvice、MethodBeforeAdviceInterceptor、AspectJAfterAdvice、AfterReturningAdviceInterceptor、AspectJAfterThrowingAdvice,上面的示例代码中包含的拦截器链就是这几个拦截器组成的。

(实际上可能不只这几个,比如上面第2步源码分析过程中,获取bean匹配的所有Advisors后,Spring将一个扩展的Advisor放到了所有Advisors列表的头部,这个也会参与组成拦截器链并且放在头部。)

紧接着上面代码中的((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this)开始,第一个MethodInterceptor是AspectJAroundAdvice登场

 // 代码位置:org.springframework.aop.aspectj.AspectJAroundAdvice#invoke
 @Override
 @Nullable
 public Object invoke(MethodInvocation mi) throws Throwable {
   if (!(mi instanceof ProxyMethodInvocation)) {
     throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
   }
   ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
   // 将mi对象包装到ProceedingJoinPoint,当我们在业务代码里使用pjp.proceed()时,就是在调用mi.proceed方法
   ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
   JoinPointMatch jpm = getJoinPointMatch(pmi);
   // 反射执行@Around注解修饰的业务切入方法
   return invokeAdviceMethod(pjp, jpm, null, null);
 }
 ​
 // 进入在Around业务方法中,会先执行Around方法前半段,然后执行pjp.proceed()
 @Around("pointCut()")
 public Object method1(ProceedingJoinPoint joinPoint) throws Throwable {
     // 执行下面两行代码 
     System.out.println("@Around... 1");
     // 这里执行过程标记为①
     Object result = joinPoint.proceed();
     
     // 暂时不会被执行,这里标记为②
     System.out.println("@Around... 2");
     return result;
 }
 ​
 // ①执行时,实际上就是pjp中的MethodInvocation对象执行proceed()方法,所以又回到了ReflectiveMethodInvocation#proceed,第二个拦截器MethodBeforeAdviceInterceptor登场
 // 代码位置:org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor#invoke
 @Override
 @Nullable
 public Object invoke(MethodInvocation mi) throws Throwable {
   // 调用@Before修饰的业务切入方法
   this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
   // 又回到了ReflectiveMethodInvocation#proceed
   return mi.proceed();
 }
 ​
 // 第三个拦截器AspectJAfterAdvice登场
 @Override
 @Nullable
 public Object invoke(MethodInvocation mi) throws Throwable {
   try {
     // 继续往下执行拦截器链或者目标方法
     return mi.proceed();
   }
   finally {
     // 执行@After修饰的业务切入方法
     // 但是因为使用finally代码块,所以需要等后续所有拦截器执行完毕之后,才进入这里,暂时不会被执行,这里标记为③
     // 从这里就可以看出来,为什么@After的执行逻辑在@AfterReturning/@AfterThrowing之后
     invokeAdviceMethod(getJoinPointMatch(), null, null);
   }
 }
 ​
 // 第四个拦截器AfterReturningAdviceInterceptor登场
 @Override
 @Nullable
 public Object invoke(MethodInvocation mi) throws Throwable {
   // 继续往下执行拦截器链或者目标方法
   Object retVal = mi.proceed();
   // 目标方法执行完成后,拿到返回值,执行@AfterReturning注解修饰的业务切入方法
   // 暂时不会被执行,这里标记为④
   this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
   return retVal;
 }
 ​
 // 第五个拦截器AspectJAfterThrowingAdvice登场
 @Override
 @Nullable
 public Object invoke(MethodInvocation mi) throws Throwable {
   try {
     // 继续往下执行拦截器链或者目标方法
     return mi.proceed();
   }
   catch (Throwable ex) {
     if (shouldInvokeOnThrowing(ex)) {
       // 当mi.proceed()出现异常时,执行@AfterThrowing注解修饰的业务切入方法,这里标记为⑤
       invokeAdviceMethod(getJoinPointMatch(), null, ex);
     }
     // 并且抛出异常,所以由此可见,当目标对象方法抛出异常时,只会执行@AfterThrowing,而不会执行@AfterReturning
     // 当目标对象方法没有抛出异常时,只会执行@AfterReturning,而不会执行@AfterThrowing
     throw ex;
   }
 }
 ​
 // 到此,五个拦截器组成的拦截链已经全部进入,AspectJAfterThrowingAdvice中mi.proceed()后,再次进入ReflectiveMethodInvocation#proceed
 // 满足if条件,执行invokeJoinpoint(),执行目标对象真正的方法
 @Override
 @Nullable
 public Object proceed() throws Throwable {
   // We start with an index of -1 and increment early.
   if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
     // 执行真目标对象真正的方法
     // 什么时候执行?等到currentInterceptorIndex等于拦截器链中最后一个的拦截器下标时,也就是执行过最后一个拦截器之后
     return invokeJoinpoint();
   }
 ​
   // ...
 }
 ​
 // 执行目标方法
 public void sayHello() {
     System.out.println("hello, i am " + name);
 }
 ​

可以看到,上面的执行链执行过程,其实就是递归过程,所以执行完目标方法后,依次会进入AspectJAfterThrowingAdvice、AfterReturningAdviceInterceptor、AspectJAfterAdvice、MethodBeforeAdviceInterceptor、AspectJAroundAdvice。

因为目标方法没有出现异常,所以后面的执行过程为④、③、②;如果抛出异常则后续的执行过程为⑤、③、②

对上面Spring拦截器链的执行过程,简单画了一个时序图,如下: Spring Aop拦截器执行链

总结

到此,基于Spring5.2.7之后的版本,从Advisors的创建,到代理对象的创建,再到代理对象执行切点方法时生成的aop拦截器链以及aop拦截器链执行的详细过程已经全部分析完成,结论前面已经说过,这里不啰嗦了。

上面一直在说Spring5.2.7版本之后,遗留了关于Spring5.2.7之前版本的几个问题,所以下面简单看一下Spring5.2.7之前版本的源码。

Spring5.2.7版本之前源码

下面的源码基于Spring5.0.12版本

1、提前创建容器中存在的所有Advisors时,存在区别
 // 代码位置:org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisors
 @Override
 public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
   Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
   // ...
 ​
   List<Advisor> advisors = new ArrayList<>();
   for (Method method : getAdvisorMethods(aspectClass)) {
     // 创建Advisor传入的declarationOrder值不是0,而是advisors的已有元素个数来决定的
     // 在这一步添加Advisor到advisors列表中,Advisor的顺序并无区别,但是后面会按照declarationOrder值排序就有问题了。
     Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
     if (advisor != null) {
       advisors.add(advisor);
     }
   }
   // ...
   return advisors;
 }
2、创建代理对象时,获取当前bean匹配上的所有Advisors,并排序

其实这一步的代码也没区别,只是因为创建Advisor时,传入的declarationOrder属性值,在这步产生了影响,这里贴一下影响点

 // 代码位置:org.springframework.aop.aspectj.autoproxy.AspectJPrecedenceComparator#comparePrecedenceWithinAspect
 ​
 private int comparePrecedenceWithinAspect(Advisor advisor1, Advisor advisor2) {
   // 调用Advisor中包装的Advice对象的isAfterAdvice()方法返回。对于@After、@AfterReturning、@AfterThrowing这三个注解对应的Advice,都会返回true
   boolean oneOrOtherIsAfterAdvice =
       (AspectJAopUtils.isAfterAdvice(advisor1) || AspectJAopUtils.isAfterAdvice(advisor2));
   int adviceDeclarationOrderDelta = getAspectDeclarationOrder(advisor1) - getAspectDeclarationOrder(advisor2);
 ​
   // 问题点就在这里,如果比较@After、@AfterReturning、@AfterThrowing这三个注解对应的Advisor,如果adviceDeclarationOrderDelta<0,那么表示优先级越低。
   // 回看declarationOrder的塞值逻辑,假设刚好只有5个Advisor,那么After、AfterReturning、AfterThrowing对应的Advisor的declarationOrder分别是2、3、4,那么经过此排序后,这三者的顺序分别是AfterThrowing、AfterReturning、After
   if (oneOrOtherIsAfterAdvice) {
     
     // the advice declared last has higher precedence
     if (adviceDeclarationOrderDelta < 0) {
       // advice1 was declared before advice2
       // so advice1 has lower precedence
       return LOWER_PRECEDENCE;
     }
     else if (adviceDeclarationOrderDelta == 0) {
       return SAME_PRECEDENCE;
     }
     else {
       return HIGHER_PRECEDENCE;
     }
   }
   else {
     // the advice declared first has higher precedence
     if (adviceDeclarationOrderDelta < 0) {
       // advice1 was declared before advice2
       // so advice1 has higher precedence
       return HIGHER_PRECEDENCE;
     }
     else if (adviceDeclarationOrderDelta == 0) {
       return SAME_PRECEDENCE;
     }
     else {
       return LOWER_PRECEDENCE;
     }
   }
 }

所以,就造成了@After比@AfterReturning/@AfterThrowing注解修饰的切入方法先执行的特点。