Spring源码解读-AOP切面执行顺序

前言

之前写过一篇关于AOP的文章,以为对AOP有了大概的了解,可最近使用下来,心中的疑惑越来越大,于是又开始了源码debug之旅,主要的疑惑有两个

  1. AOP切面的执行优先级
  2. AOP切面的参数是如何传递的

此处吐槽一下AOP的一大堆概念,什么连接点,通知,十分好奇是不是翻译得不好

Advice与Advisor

我们经常会看到Advice、Advisor,他们代表什么呢?

Advice是通知,Advisor是增强器,每个Advisor都会持有一个Advice,这个解释看起来是不是还是很抽象,我也是这样觉得,还是用代码来解释比较好,我写了这样的一个切面,里面有一个方法,Spring为了便于管理和做一些额外的功能,会怎么包装呢?

@Aspect
@Component
public class AspectDemo {
​
   @Pointcut("@annotation(aspectAnnotation)")
   public void test(AspectAnnotation aspectAnnotation) {
   }
​
   @Before("test(aspectAnnotation)")
   public void before(JoinPoint p, AspectAnnotation aspectAnnotation) {
      System.out.println("before test..");
   }
}
复制代码

这个参数在下文有具体的解释,大家先看个眼熟,先记住一个结论,切面中的方法会被Spring包装成一个个的Advisor和Advice

Spring源码解读-AOP切面执行顺序_第1张图片

Spring源码解读-AOP切面执行顺序_第2张图片

那Advisor具体长什么样子呢?它有一个很重要的实现InstantiationModelAwarePointcutAdvisorImpl,我们来看看

final class InstantiationModelAwarePointcutAdvisorImpl
    implements InstantiationModelAwarePointcutAdvisor, AspectJPrecedenceInformation, Serializable {
​
  private static final Advice EMPTY_ADVICE = new Advice() {};
  // 切点,对象包含了切点的表达式,入参,beanFactory等信息
  private final AspectJExpressionPointcut declaredPointcut;
  // @Aspect注解所在的类的Class
  private final Class declaringClass;
  // Advice的方法名
  private final String methodName;
  // Advice入参的参数类型
  private final Class[] parameterTypes;
  // Advice对应的Method
  private transient Method aspectJAdviceMethod;
  // Advice生成的工厂
  private final AspectJAdvisorFactory aspectJAdvisorFactory;
  // 这个工厂类的实现BeanFactoryAspectInstanceFactory,在切面排序中发挥关键作用
  private final MetadataAwareAspectInstanceFactory aspectInstanceFactory;
  // 切面的优先级,目前被硬编码为0
  private final int declarationOrder;
  // @Aspect注解所在的类的类名
  private final String aspectName;
  // 持有的数据跟declaredPointcut类似,猜测是历史负债所做的兼容
  private final Pointcut pointcut;
  // Advisor持有的Advice实例
  @Nullable
  private Advice instantiatedAdvice;
}
复制代码

看到上面这些信息,这个类仿佛是在对我们说我从哪里来,我要做什么,比起我从哪里来,我们更关注我要做什么——Advice,Advice也是一个接口,我们看看下图他的亲人们,看名字是不是很熟悉,最下面的5个类分别对应@AfterReturning、@AfterThrowing、@After、@Around、@Before

Spring源码解读-AOP切面执行顺序_第3张图片

他们都有一个共同的抽象类AbstractAspectJAdvice,先看看这个类的成员变量能更好地理解下面的代码

public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedenceInformation, Serializable {
   // @Aspect注解所在的类的Class
   private final Class declaringClass;
   // Advice的方法名
   private final String methodName;
   // Advice入参的参数类型
   private final Class[] parameterTypes;
   // Advice对应的Method
   protected transient Method aspectJAdviceMethod;
   // 切点,对象包含了切点的表达式,入参,beanFactory等信息
   private final AspectJExpressionPointcut pointcut;
   // 这个工厂类的实现BeanFactoryAspectInstanceFactory,在切面排序中发挥关键作用
   private final AspectInstanceFactory aspectInstanceFactory;
​
   // @Aspect注解所在的类的类名
   private String aspectName = "";
   // 切面的优先级,目前被硬编码为0
   private int declarationOrder;
   // Advice入参的参数名
   @Nullable
   private String[] argumentNames;
   // 当注解为@AfterThrowing且throwing值不为空时,throwing的值
   @Nullable
   private String throwingName;
   // 当注解为@AfterReturning且returning值不为空时,returning的值
   @Nullable
   private String returningName;
   // 当注解为@AfterReturning且returning值不为空时,返回值的Class
   private Class discoveredReturningType = Object.class;
   // 当注解为@AfterThrowing且throwing值不为空时,返回值的Class
   private Class discoveredThrowingType = Object.class;
   // 如果Advice对应的方法的第一个入参是JoinPoint或者ProceedingJoinPoint类型,这个值为0
   private int joinPointArgumentIndex = -1;
   // 如果Advice对应的方法的第一个入参是JoinPoint.StaticPart,这个值为0
   private int joinPointStaticPartArgumentIndex = -1;
   // Advice未绑定的参数名称及参数的排序
   @Nullable
   private Map argumentBindings;
​
   private boolean argumentsIntrospected = false;
    
   // 当注解为@AfterReturning且returning值不为空时,返回值的泛型
   @Nullable
   private Type discoveredReturningGenericType;
}
复制代码

再看看其中一个继承了抽象类的切面,整个类很简单,只有一个反射的调用,说明抽象类承载了大部分的功能,并且所有注解的步骤都是类似的,可以整合到一起

public class AspectJAfterAdvice extends AbstractAspectJAdvice
      implements MethodInterceptor, AfterAdvice, Serializable {
   public AspectJAfterAdvice(
         Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
​
      super(aspectJBeforeAdviceMethod, pointcut, aif);
   }
   // 反射调用真正的方法
   @Override
   public Object invoke(MethodInvocation mi) throws Throwable {
      try {
         return mi.proceed();
      }
      finally {
         invokeAdviceMethod(getJoinPointMatch(), null, null);
      }
   }
   @Override
   public boolean isBeforeAdvice() {
      return false;
   }
   @Override
   public boolean isAfterAdvice() {
      return true;
}
复制代码

看完上面琐碎的背景,我们来看一个Advice的创建过程,串联一下知识点

// 这个方法位于InstantiationModelAwarePointcutAdvisorImpl中,实例化Advice
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
    Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
    this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
    return (advice != null ? advice : EMPTY_ADVICE);
}
​
​
@Override
@Nullable
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
                        MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
​
    ......
​
    AbstractAspectJAdvice springAdvice;
​
    // 根据注解类型生成不同的通知实例
    // 对应的注解就是@Around、@Before、@After、@AfterReturning、@AfterThrowing
    switch (aspectJAnnotation.getAnnotationType()) {
      case AtPointcut:
        if (logger.isDebugEnabled()) {
          logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
        }
        return null;
      case AtAround:
        springAdvice = new AspectJAroundAdvice(
          candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
        break;
      case AtBefore:
        springAdvice = new AspectJMethodBeforeAdvice(
          candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
        break;
      case AtAfter:
        springAdvice = new AspectJAfterAdvice(
          candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
        break;
      case AtAfterReturning:
        springAdvice = new AspectJAfterReturningAdvice(
          candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
        AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
        // 当注解中的参数returning不为空时,设置该值
        if (StringUtils.hasText(afterReturningAnnotation.returning())) {
          springAdvice.setReturningName(afterReturningAnnotation.returning());
        }
        break;
      case AtAfterThrowing:
        springAdvice = new AspectJAfterThrowingAdvice(
          candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
        AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
        // 当注解中的参数throwing不为空时,设置该值
        if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
          springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
        }
        break;
      default:
        throw new UnsupportedOperationException(
          "Unsupported advice type on method: " + candidateAdviceMethod);
    }
​
​
    // 设置Advice所属的类
    springAdvice.setAspectName(aspectName);
    springAdvice.setDeclarationOrder(declarationOrder);
    // 获取Advice的所有参数
    String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
    if (argNames != null) {
      // 将通知方法上的参数设置到通知中
      springAdvice.setArgumentNamesFromStringArray(argNames);
    }
    springAdvice.calculateArgumentBindings();
​
  return springAdvice;
}
复制代码

以下是解析切面注解上的参数,代码写得很难理解,我一步一步debug给大家看,还是上面那个方法,那个类有两个入参

public final synchronized void calculateArgumentBindings() {
   // 如果方法没有入参,也就是不需要绑定参数,直接返回
   if (this.argumentsIntrospected || this.parameterTypes.length == 0) {
      return;
   }
   // numUnboundArgs为未计划好的参数绑定数量
   int numUnboundArgs = this.parameterTypes.length;
   Class[] parameterTypes = this.aspectJAdviceMethod.getParameterTypes();
   // 切面注解标识方法第一个参数要求是JoinPoint或者JoinPoint.StaticPart
   // 若是@Around注解则也可以是ProceedingJoinPoint
   if (maybeBindJoinPoint(parameterTypes[0]) || maybeBindProceedingJoinPoint(parameterTypes[0]) ||
         maybeBindJoinPointStaticPart(parameterTypes[0])) {
      numUnboundArgs--;
   }
​
   if (numUnboundArgs > 0) {
      // 继续按照名称绑定参数
      bindArgumentsByName(numUnboundArgs);
   }
​
   this.argumentsIntrospected = true;
}
复制代码

入参中第一个参数如果是JoinPoint、JoinPoint.StaticPart、ProceedingJoinPoint,固定排在第一位,并且 joinPointArgumentIndex或者 joinPointStaticPartArgumentIndex会被设置为0,其它入参则是未绑定参数,下文会继续进行绑定

Spring源码解读-AOP切面执行顺序_第4张图片

​
private void bindArgumentsByName(int numArgumentsExpectingToBind) {
    if (this.argumentNames == null) {
      // 获取方法参数的名称
      this.argumentNames = createParameterNameDiscoverer().getParameterNames(this.aspectJAdviceMethod);
    }
    if (this.argumentNames != null) {
      // We have been able to determine the arg names.
      bindExplicitArguments(numArgumentsExpectingToBind);
    }
    ......
}
​
​
​
​
​
private void bindExplicitArguments(int numArgumentsLeftToBind) {
    Assert.state(this.argumentNames != null, "No argument names available");
    // 此属性用来存储方法未绑定的参数名称及参数的序号
    this.argumentBindings = new HashMap<>();
​
    int numExpectedArgumentNames = this.aspectJAdviceMethod.getParameterCount();
    if (this.argumentNames.length != numExpectedArgumentNames) {
      throw new IllegalStateException("Expecting to find " + numExpectedArgumentNames +
                                      " arguments to bind by name in advice, but actually found " +
                                      this.argumentNames.length + " arguments.");
    }
​
    // argumentIndexOffset表示第一个未绑定参数的顺序
    int argumentIndexOffset = this.parameterTypes.length - numArgumentsLeftToBind;
    for (int i = argumentIndexOffset; i < this.argumentNames.length; i++) {
      // 存储未绑定的参数名称及其映射顺序
      this.argumentBindings.put(this.argumentNames[i], i);
    }
​
    // Check that returning and throwing were in the argument names list if
    // specified, and find the discovered argument types.
    // 如果@AfterReturn
    if (this.returningName != null) {
      if (!this.argumentBindings.containsKey(this.returningName)) {
        throw new IllegalStateException("Returning argument name '" + this.returningName +
                                        "' was not bound in advice arguments");
      }
      else {
        // 获取该入参的参数顺序
        Integer index = this.argumentBindings.get(this.returningName);
        // 设置返回值Class
        this.discoveredReturningType = this.aspectJAdviceMethod.getParameterTypes()[index];
        // 在返回值有泛型的情况下,设置返回值泛型
        this.discoveredReturningGenericType = this.aspectJAdviceMethod.getGenericParameterTypes()[index];
      }
    }
    // 如果是@AfterThrowing
    if (this.throwingName != null) {
      if (!this.argumentBindings.containsKey(this.throwingName)) {
        throw new IllegalStateException("Throwing argument name '" + this.throwingName +
                                        "' was not bound in advice arguments");
      }
      else {
        // 获取该入参的参数顺序
        Integer index = this.argumentBindings.get(this.throwingName);
        // 设置异常Class
        this.discoveredThrowingType = this.aspectJAdviceMethod.getParameterTypes()[index];
      }
    }
​
    // configure the pointcut expression accordingly.
    configurePointcutParameters(this.argumentNames, argumentIndexOffset);
}
复制代码

Spring源码解读-AOP切面执行顺序_第5张图片

// 这个方法会将所有未绑定参数的名字和类型存储在切点中,待后续使用
private void configurePointcutParameters(String[] argumentNames, int argumentIndexOffset) {
   int numParametersToRemove = argumentIndexOffset;
   if (this.returningName != null) {
      numParametersToRemove++;
   }
   if (this.throwingName != null) {
      numParametersToRemove++;
   }
   String[] pointcutParameterNames = new String[argumentNames.length - numParametersToRemove];
   Class[] pointcutParameterTypes = new Class[pointcutParameterNames.length];
   Class[] methodParameterTypes = this.aspectJAdviceMethod.getParameterTypes();
​
   int index = 0;
   for (int i = 0; i < argumentNames.length; i++) {
      if (i < argumentIndexOffset) {
         continue;
      }
      if (argumentNames[i].equals(this.returningName) ||
         argumentNames[i].equals(this.throwingName)) {
         continue;
      }
      pointcutParameterNames[index] = argumentNames[i];
      pointcutParameterTypes[index] = methodParameterTypes[i];
      index++;
   }
​
   this.pointcut.setParameterNames(pointcutParameterNames);
   this.pointcut.setParameterTypes(pointcutParameterTypes);
}
复制代码

Spring源码解读-AOP切面执行顺序_第6张图片

Advisor的排序

如果一个方法打了多个切面注解,这个方法就会对应多个Advisor,这个时候哪个Advisor先执行,哪个Advisor后执行就是一个很大的问题,这个问题很严重,千万别小看

到达排序的调用链很深,我们直接到排序相关的方法

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary

org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean

org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator#sortAdvisors

private static final Comparator DEFAULT_PRECEDENCE_COMPARATOR = new AspectJPrecedenceComparator();
​
@Override
protected List sortAdvisors(List advisors) {
   // 使用PartiallyComparableAdvisorHolder对Advisor进行了包装,加入了DEFAULT_PRECEDENCE_COMPARATOR这个比较器 
   List partiallyComparableAdvisors = new ArrayList<>(advisors.size());
   for (Advisor advisor : advisors) {
      partiallyComparableAdvisors.add(
            new PartiallyComparableAdvisorHolder(advisor, DEFAULT_PRECEDENCE_COMPARATOR));
   }
   List sorted = PartialOrder.sort(partiallyComparableAdvisors);
   if (sorted != null) {
      List result = new ArrayList<>(advisors.size());
      for (PartiallyComparableAdvisorHolder pcAdvisor : sorted) {
         result.add(pcAdvisor.getAdvisor());
      }
      return result;
   }
   else {
      return super.sortAdvisors(advisors);
   }
}
复制代码
public AspectJPrecedenceComparator() {
   // 构造器中加入了一个比较器
   this.advisorComparator = AnnotationAwareOrderComparator.INSTANCE;
}
​
​
@Override
public int compare(Advisor o1, Advisor o2) {
    // 这个方法有两重比较,首先用advisorComparator进行比较
    int advisorPrecedence = this.advisorComparator.compare(o1, o2);
    // 顺序相同,且来源同一aspect,调用comparePrecedenceWithinAspect再次比较
    if (advisorPrecedence == SAME_PRECEDENCE && declaredInSameAspect(o1, o2)) {
      advisorPrecedence = comparePrecedenceWithinAspect(o1, o2);
    }
    return advisorPrecedence;
}
复制代码
@Override
public int compare(@Nullable Object o1, @Nullable Object o2) {
   return doCompare(o1, o2, null);
}
​
private int doCompare(@Nullable Object o1, @Nullable Object o2, @Nullable OrderSourceProvider sourceProvider) {
   // 两者之一为PriorityOrdered,谁是PriorityOrdered,谁的优先级高,在Advisor的比较中,这个是不起作用的
   // 因为Advisor都被包装成了InstantiationModelAwarePointcutAdvisorImpl,这个类没有实现PriorityOrdered
   boolean p1 = (o1 instanceof PriorityOrdered);
   boolean p2 = (o2 instanceof PriorityOrdered);
   if (p1 && !p2) {
      return -1;
   }
   else if (p2 && !p1) {
      return 1;
   }
   // 两者都是Ordered,根据getOrder()返回的值做比较,值越小优先级越高
   int i1 = getOrder(o1, sourceProvider);
   int i2 = getOrder(o2, sourceProvider);
   return Integer.compare(i1, i2);
}
复制代码

getOrder()的调用链比较深,此处先说结论

  1. 如果实现了Ordered或者PriorityOrdered,根据返回值做比较,值越小优先级越高
  2. 如果标注了@Order或者@Priority注解,则根据value()值做比较,值越小优先级
  3. 如果没有实现Ordered或者PriorityOrdered,也没有打注解,则为最低优先级(Integer.MAX_VALUE)

以上的比较中,注解返回的值和接口返回的值是一起比较,并没有哪一个比较优先的说法

getOrder()的调用链

org.springframework.core.OrderComparator#getOrder

org.springframework.core.OrderComparator#findOrder

org.springframework.aop.aspectj.annotation.InstantiationModelAwarePointcutAdvisorImpl#getOrder

org.springframework.aop.aspectj.annotation.BeanFactoryAspectInstanceFactory#getOrder

下面这个是比较关键的方法

@Override
public int getOrder() {
   // 在IOC容器中查找切面类,切面类是指打了@Aspect注解的类,这个赋值是在形成Advisor的时候赋好的 
   Class type = this.beanFactory.getType(this.name);
   if (type != null) {
      // 如果切面类实现了Ordered或者PriorityOrdered,直接获取接口的返回值
      if (Ordered.class.isAssignableFrom(type) && this.beanFactory.isSingleton(this.name)) {
         return ((Ordered) this.beanFactory.getBean(this.name)).getOrder();
      }
      // 如果没有实现Ordered或者PriorityOrdered,则获取@Order或者@Priority注解中的值
      // 如果注解中也没有值,则返回Integer.MAX_VALUE
      return OrderUtils.getOrder(type, Ordered.LOWEST_PRECEDENCE);
   }
   // 
   return Ordered.LOWEST_PRECEDENCE;
}
复制代码

以上的比较是基于不同的切面进行的比较,如果同一个切面,比如一个切面中有多个@After的方法,要如何比较呢?这个比较有两个步骤

  1. 在获取切面中有多少个方法需要形成Advisor时,会根据注解的顺序先进行一次排序

org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisors

org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisorMethods

private List getAdvisorMethods(Class aspectClass) {
   final List methods = new ArrayList<>();
   ReflectionUtils.doWithMethods(aspectClass, method -> {
      // 除去Pointcut注解
      if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
         methods.add(method);
      }
   }, ReflectionUtils.USER_DECLARED_METHODS);
   if (methods.size() > 1) {
      // 对所有advisors方法进行排序
      methods.sort(METHOD_COMPARATOR);
   }
   return methods;
}
​
private static final Comparator METHOD_COMPARATOR;
​
static {
  // 按照@Around、@Before、@After、@AfterReturning、@AfterThrowing的顺序
  Comparator adviceKindComparator = new ConvertingComparator<>(
    new InstanceComparator<>(
      Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
    (Converter) method -> {
      AspectJAnnotation ann = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
      return (ann != null ? ann.getAnnotation() : null);
    });
  Comparator methodNameComparator = new ConvertingComparator<>(Method::getName);
  METHOD_COMPARATOR = adviceKindComparator.thenComparing(methodNameComparator);
}
复制代码
  1. 还有一段这样的代码,这段代码的意思就是每个Advisor都有一个对应declarationOrder,根据这个来做优先级的排序,非常可惜,所有的Advisor的declarationOrder都被写死了0,也就是优先级都是相等的,代码位于org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisors,Spring也非常贴心地写了一段我没看懂注释,我查了一些资料,个人理解如下:在Spring Framework 5.2.7之前,advisor.size()是作为declarationOrder的值的,也就是说list中的排序就是declarationOrder的值,但是从Java 7开始,当前位置不再有效,因为JDK不再有效返回在源代码中声明方法的顺序,仅靠SpirngAOP是无法保证排序的,此外,如果类被混淆、JVM或者编译器不同,其结果也可能会改变
private int comparePrecedenceWithinAspect(Advisor advisor1, Advisor advisor2) {
   // 其中一个是否存在@After注解
   boolean oneOrOtherIsAfterAdvice =
         (AspectJAopUtils.isAfterAdvice(advisor1) || AspectJAopUtils.isAfterAdvice(advisor2));
   int adviceDeclarationOrderDelta = getAspectDeclarationOrder(advisor1) - getAspectDeclarationOrder(advisor2);
   // 其中有一个是after通知,declarationOrder大的优先级高
   if (oneOrOtherIsAfterAdvice) {
      if (adviceDeclarationOrderDelta < 0) {
         return LOWER_PRECEDENCE;
      }
      else if (adviceDeclarationOrderDelta == 0) {
         return SAME_PRECEDENCE;
      }
      else {
         return HIGHER_PRECEDENCE;
      }
   }
   // 两个都不是after通知,declarationOrder小的优先级高
   else {
      if (adviceDeclarationOrderDelta < 0) {
         return HIGHER_PRECEDENCE;
      }
      else if (adviceDeclarationOrderDelta == 0) {
         return SAME_PRECEDENCE;
      }
      else {
         return LOWER_PRECEDENCE;
      }
   }
}
复制代码

Advice的参数传递

调用链还是很深,只讲关键的方法

org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor#intercept

org.springframework.aop.framework.CglibAopProxy.CglibMethodInvocation#proceed

org.springframework.aop.framework.ReflectiveMethodInvocation#proceed

org.springframework.aop.interceptor.ExposeInvocationInterceptor#invoke

org.springframework.aop.framework.CglibAopProxy.CglibMethodInvocation#proceed

org.springframework.aop.framework.ReflectiveMethodInvocation#proceed

org.springframework.aop.aspectj.AspectJAroundAdvice#invoke

org.springframework.aop.aspectj.AbstractAspectJAdvice#invokeAdviceMethod(org.aspectj.lang.JoinPoint, org.aspectj.weaver.tools.JoinPointMatch, java.lang.Object, java.lang.Throwable)

org.springframework.aop.aspectj.AbstractAspectJAdvice#invokeAdviceMethodWithGivenArgs

protected Object[] argBinding(JoinPoint jp, @Nullable JoinPointMatch jpMatch,
      @Nullable Object returnValue, @Nullable Throwable ex) {
   // 这个方法上面已经解读过,重复调用一次而已
   calculateArgumentBindings();
​
   // 根据Advice入参的数量创建数组,这个数组是真正进行反射调用时的入参
   Object[] adviceInvocationArgs = new Object[this.parameterTypes.length];
   int numBound = 0;
   // this.joinPointArgumentIndex不为-1,表示Advice对应的方法的第一个入参是JoinPoint或者ProceedingJoinPoint类型
   if (this.joinPointArgumentIndex != -1) {
      adviceInvocationArgs[this.joinPointArgumentIndex] = jp;
      numBound++;
   }
   // this.joinPointStaticPartArgumentIndex不为-1.表示Advice对应的方法的第一个入参是JoinPoint.StaticPart
   else if (this.joinPointStaticPartArgumentIndex != -1) {
      adviceInvocationArgs[this.joinPointStaticPartArgumentIndex] = jp.getStaticPart();
      numBound++;
   }
​
   if (!CollectionUtils.isEmpty(this.argumentBindings)) {
      if (jpMatch != null) {
         // 根据切点进行参数的匹配
         PointcutParameter[] parameterBindings = jpMatch.getParameterBindings();
         for (PointcutParameter parameter : parameterBindings) {
            // 根据参数的名字获取入参的顺序
            String name = parameter.getName();
            Integer index = this.argumentBindings.get(name);
            adviceInvocationArgs[index] = parameter.getBinding();
            numBound++;
         }
      }
      // 当注解为@AfterReturning且returning值不为空时,进行赋值
      if (this.returningName != null) {
         Integer index = this.argumentBindings.get(this.returningName);
         adviceInvocationArgs[index] = returnValue;
         numBound++;
      }
      // 当注解为@AfterThrowing且throwing值不为空时,进行赋值
      if (this.throwingName != null) {
         Integer index = this.argumentBindings.get(this.throwingName);
         adviceInvocationArgs[index] = ex;
         numBound++;
      }
   }
​
   if (numBound != this.parameterTypes.length) {
      throw new IllegalStateException("Required to bind " + this.parameterTypes.length +
            " arguments, but only bound " + numBound + " (JoinPointMatch " +
            (jpMatch == null ? "was NOT" : "WAS") + " bound in invocation)");
   }
​
   return adviceInvocationArgs;
}
复制代码
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
   Object[] actualArgs = args;
   // 如果增强方法没有参数,将actualArgs设置为null
   if (this.aspectJAdviceMethod.getParameterCount() == 0) {
      actualArgs = null;
   }
   try {
      ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
      // 反射增强方法
      return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
   }
   ......
}
复制代码

至此,文章开头提到的疑惑稍微有了点眉目

你可能感兴趣的:(java,spring,java,后端)