搜索
您的当前位置:首页正文

spring (四)AOP源码分析 五种通知的执行顺序

来源:好走旅游网
声明:本系列源码版本为4.3.12,本文结论与spring5有些许出入,意在阅读思路,如果能认真读完本文可以自行了解spring5相关部分的改动。

开篇之前先说个很无奈的事情,笔者以前面试的时候有被问到过是否了解AOP的增强,当时的我一脸懵逼
,什么是增强?后来查了下,增强也就是通知。

通知的执行顺序

通知的执行顺序分两种情况

1、首先是目标方法没有异常的情况:
环绕通知、前置通知、目标方法、环绕通知,后置通知、返回通知

2、目标方法有异常的顺序:
环绕通知、前置通知、目标方法、后置通知、异常通知

所以各通知执行时机为

@Around:环绕通知:前置通知之前执行proceed方法之前的部分
@Before:前置通知,目标方法之前执行
执行目标方法
@Around:环绕通知:目标方法执行之后(如果有环绕通知会在环绕通知proceed方法之后部分执行之后)执行proceed方法之后的部分
@After:后置通知,目标方法之后执行
@AfterReturning:目标方法正常放回执行
@AfterThrowing:目标方法出现异常时执行
其中@AfterReturning和@AfterThrowing只有一个会执行

源码分析

切面类

@Aspect
public class LogAspects {
   
   //抽取公共的切入点表达式
   //1、本类引用
   //2、其他的切面引用
   @Pointcut("execution(public int com.ethan.aop.MyCalculator.*(..))")
   public void pointCut(){};
   
   //@Before在目标方法之前切入;切入点表达式(指定在哪个方法切入)
   @Before("pointCut()")
   public void logStart(JoinPoint joinPoint){
      Object[] args = joinPoint.getArgs();
      System.out.println(""+joinPoint.getSignature().getName()+"运行。。。@Before:参数列表是:{"+Arrays.asList(args)+"}");
   }
   
   @After("com.ethan.aop.LogAspects.pointCut()")
   public void logEnd(JoinPoint joinPoint){
      System.out.println(""+joinPoint.getSignature().getName()+"结束。。。@After");
   }
   
   //JoinPoint一定要出现在参数表的第一位
   @AfterReturning(value="pointCut()",returning="result")
   public void logReturn(JoinPoint joinPoint,Object result){
      System.out.println(""+joinPoint.getSignature().getName()+"正常返回。。。@AfterReturning:运行结果:{"+result+"}");
   }
   
   @AfterThrowing(value="pointCut()",throwing="exception")
   public void logException(JoinPoint joinPoint,Exception exception){
      System.out.println(""+joinPoint.getSignature().getName()+"异常。。。异常信息:{"+exception+"}");
   }

   @Around(value="pointCut()")
   public void logAround(ProceedingJoinPoint joinPoint) throws Throwable {
      System.out.println("around before proceed");

      joinPoint.proceed();
      System.out.println("around after proceed ");
   }

}

配置类

@EnableAspectJAutoProxy
@Configuration
public class MainConfigOfAOP {
    
   //业务逻辑类加入容器中
   @Bean
   public MyCalculator calculator(){
      return new MyCalculator();
   }

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

业务类

public class MyCalculator {
   
   public int div(int i,int j){
      System.out.println("MathCalculator...div...");
      return i/j;    
   }

}

本例会创建cglib动态代理,具体原理可查看,我们在测试类方法调用之前打个断点可以看到获得的对象已经是代理对象

接下来步进执行:进入CglibAopProxy类的intercept方法
看一下主要代码

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
   Object oldProxy = null;
   boolean setProxyContext = false;
   Class<?> targetClass = null;
   Object target = null;
   try {
      if (this.advised.exposeProxy) {
         // Make invocation available if necessary.
         oldProxy = AopContext.setCurrentProxy(proxy);
         setProxyContext = true;
      }
      // May be null. Get as late as possible to minimize the time we
      // "own" the target, in case it comes from a pool...
      target = getTarget();
      if (target != null) {
         targetClass = target.getClass();
      }
      //获得拦截器链
      List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
      Object retVal;
      // Check whether we only have one InvokerInterceptor: that is,
      // no real advice, but just reflective invocation of the target.
      if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
         // 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 = methodProxy.invoke(target, argsToUse);
      }
      else {
         // We need to create a method invocation...
         //如果没有拦截器链,直接执行目标方法
         retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
      }
      retVal = processReturnType(proxy, target, method, retVal);
      return retVal;
   }
   finally {
      if (target != null) {
         releaseTarget(target);
      }
      if (setProxyContext) {
         // Restore old proxy.
         AopContext.setCurrentProxy(oldProxy);
      }
   }
}

该方法根据ProxyFactory对象(this.advised)获取将要执行的目标方法拦截器链; List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);如果没有拦截器链,直接执行目标方法 retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
接下来看怎么获得拦截器链:

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
   MethodCacheKey cacheKey = new MethodCacheKey(method);
   List<Object> cached = this.methodCache.get(cacheKey);
   if (cached == null) {
      cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
            this, method, targetClass);
      this.methodCache.put(cacheKey, cached);
   }
   return cached;
}

getInterceptorsAndDynamicInterceptionAdvice方法会遍历所有的增强器,将其转为Interceptor;
其中第一个是默认的ExposeInvocationInterceptor,剩下的是我们在切面定义好的五个增强器,

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
      Advised config, Method method, Class<?> targetClass) {

   // This is somewhat tricky... We have to process introductions first,
   // but we need to preserve order in the ultimate list.
   List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
   Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
   boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
   AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();

   for (Advisor advisor : config.getAdvisors()) {
      if (advisor instanceof PointcutAdvisor) {
         // Add it conditionally.
         PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
         if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
            MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
            MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
            if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
               if (mm.isRuntime()) {
                  // Creating a new object instance in the getInterceptors() method
                  // isn't a problem as we normally cache created chains.
                  for (MethodInterceptor interceptor : interceptors) {
                     interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                  }
               }
               else {
                  interceptorList.addAll(Arrays.asList(interceptors));
               }
            }
         }
      }
      // 如果是MethodInterceptor,直接加入到集合中
 //如果不是,使用AdvisorAdapter将增强器转为MethodInterceptor;

      else if (advisor instanceof IntroductionAdvisor) {
         IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
         if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
            Interceptor[] interceptors = registry.getInterceptors(advisor);
            interceptorList.addAll(Arrays.asList(interceptors));
         }
      }
      else {
         Interceptor[] interceptors = registry.getInterceptors(advisor);
         interceptorList.addAll(Arrays.asList(interceptors));
      }
   }

   return interceptorList;
}

可以看到 registry.getInterceptors(advisor)这个方法,它的作用是:
如果增强器是MethodInterceptor类型的,直接加入到集合中
如果不是,使用AdvisorAdapter将增强器转为MethodInterceptor;
转换完成返回MethodInterceptor数组;

public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
   List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);
   Advice advice = advisor.getAdvice();
   if (advice instanceof MethodInterceptor) {
      interceptors.add((MethodInterceptor) advice);
   }
   for (AdvisorAdapter adapter : this.adapters) {
      if (adapter.supportsAdvice(advice)) {
         interceptors.add(adapter.getInterceptor(advisor));
      }
   }
   if (interceptors.isEmpty()) {
      throw new UnknownAdviceTypeException(advisor.getAdvice());
   }
   return interceptors.toArray(new MethodInterceptor[interceptors.size()]);
}

这样做的意图很明显,说明增强器里面并不都是MethodInterceptor类型的,下面我们列出所有增强器的顺序,并标注他们是否是MethodInterceptor类型的
ExposeInvocationInterceptor:是
AspectJAfterThrowingAdvice: 是
AspectJAfterReturningAdvice: 不是,转换为AfterReturningAdviceInterceptor
AspectJAfterAdvice: 是
AspectJAroundAdvice 是
AspectJMethodBeforeAdvice 不是,转换为MethodBeforeAdviceInterceptor

现在我们获得了拦截器,就要看执行方法了proceed()

retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();

查看源码

public Object proceed() throws Throwable {
   // We start with an index of -1 and increment early.
   if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
      return invokeJoinpoint();
   }

   Object interceptorOrInterceptionAdvice =
         this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
   if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
      // Evaluate dynamic method matcher here: static part will already have
      // been evaluated and found to match.
      InterceptorAndDynamicMethodMatcher dm =
            (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
      if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
         return dm.interceptor.invoke(this);
      }
      else {
         // Dynamic matching failed.
         // Skip this interceptor and invoke the next in the chain.
         return proceed();
      }
   }
   else {
      // It's an interceptor, so we just invoke it: The pointcut will have
      // been evaluated statically before this object was constructed.
      return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
   }
}

这里是重点,首先if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); }
currentInterceptorIndex 初始化为-1,拿-1和this.interceptorsAndDynamicMethodMatchers.size() - 1比较,如果相等,执行invokeJoinpoint方法,而此方法就是利用反射执行目标方法,此处条件成立只有currentInterceptorIndex 等于interceptorsAndDynamicMethodMatchers.size() - 1的时候,这证明,后续有currentInterceptorIndex 加1的操作。我们往下看Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);

果然这里进行了++操作,继续看后续代码,如果根据get方法获得的interceptorOrInterceptionAdvice属于InterceptorAndDynamicMethodMatcher()就进行一些操作if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {,我们的五个增强器都不满足条件,则执行else语句,return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
查看invoke方法

public Object invoke(MethodInvocation mi) throws Throwable {
   MethodInvocation oldInvocation = invocation.get();
   invocation.set(mi);
   try {
      return mi.proceed();
   }
   finally {
      invocation.set(oldInvocation);
   }
}

调用 mi.proceed();,而这个方法又会回到ReflectiveMethodInvocation的proceed方法,以此达到递归效果,接下来遍历AspectJAfterThrowingAdvice,执行invoke方法,

public Object invoke(MethodInvocation mi) throws Throwable {
   try {
   //继续递归
      return mi.proceed();
   }
   catch (Throwable ex) {
      if (shouldInvokeOnThrowing(ex)) {
      //如果方法返回之前捕获异常,则执行invokeAdviceMethod方法
         invokeAdviceMethod(getJoinPointMatch(), null, ex);
      }
      throw ex;
   }
}

可以看到如果方法返回之前捕获异常,则执行invokeAdviceMethod方法,这也是解释为什么只有出现异常,异常通知才会执行
接下来是第三个通知AfterReturningAdviceInterceptor,查看源码:

public Object invoke(MethodInvocation mi) throws Throwable {
   Object retVal = mi.proceed();
   this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
   return retVal;
}

可以看到,在方法mi.proceed()返回之后,会执行this.advice.afterReturning方法;那么只要mi.proceed()方法有任何异常,都不会执行afterReturning方法

这样,下一个增强器AspectJAfterAdvice出场:

public Object invoke(MethodInvocation mi) throws Throwable {
   try {
      return mi.proceed();
   }
   finally {
      invokeAdviceMethod(getJoinPointMatch(), null, null);
   }
}

这里我们看到finally块里面执行了invokeAdviceMethod方法,也就是说无论是否出现异常,都会执行后置通知的方法

继续看下一个通知AspectJAroundAdvice

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;
   ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
   JoinPointMatch jpm = getJoinPointMatch(pmi);
   return invokeAdviceMethod(pjp, jpm, null, null);
}

环绕通知比较特别,可以看到它并没有继续递归,但是invokeAdviceMethod方法会执行通知方法joinPoint.proceed();之前的代码

@Around(value="pointCut()")
public void logAround(ProceedingJoinPoint joinPoint) throws Throwable {
   System.out.println("around before proceed");

   joinPoint.proceed();
   System.out.println("around after proceed ");
}

当执行到 joinPoint.proceed();时,会再次进去递归当中

public Object proceed() throws Throwable {
   return this.methodInvocation.invocableClone().proceed();
}

这样,就可以看最后一个增强:MethodBeforeAdviceInterceptor

public Object invoke(MethodInvocation mi) throws Throwable {
   this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
   return mi.proceed();
}

可以看到,首先执行before前置方法,然后 mi.proceed();但是此时this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1条件成立,执行目标方法,接着返回到MethodBeforeAdviceInterceptor的invoke方法,每个增强器逐层返回。

这样,就达到了文章一开始说的执行顺序。

总结

先列出拦截器链中的顺序
1:默认 ExposeInvocationInterceptor
2:异常通知 AspectJAfterThrowingAdvice
3:返回通知 AspectJAfterReturningAdvice->AfterReturningAdviceInterceptor
4:后置通知 AspectJAfterAdvice
5:环绕通知 AspectJAroundAdvice
6:前置通知 AspectJMethodBeforeAdvice->MethodBeforeAdviceInterceptor

invoke调用顺序为:
1-2-3-4-5(joinPoint.proceed()之前的部分先执行,通过proceed继续递归)-6

那么invoke方法里面各个对应的通知方法执行顺序为:
5的前一部分(因为在invoke方法中已经先执行)–6(递归的最后一层)–目标方法(递归结束执行目标方法)–返回到5的后一部分–返回到4(finally块必会执行)–返回到3(有异常逃过不执行)–返回到2(try块里有异常才执行)–返回到1默认拦截器方法

因篇幅问题不能全部显示,请点此查看更多更全内容

Top