• Spring-AOP源码分析随手记(二)


    这次来分析下切面的执行过程。

    1.怎么看?

    怎么开始看源码呢?就直接从被增强的方法调用那里打断点,看看怎么执行的:

    image

    然后就来到了这:

    image

    image

    2.初步分析

    里面有段:

    if (this.advised.exposeProxy) {
       // Make invocation available if necessary.
       oldProxy = AopContext.setCurrentProxy(proxy);
       setProxyContext = true;
    }
    

    就是上篇文章讲到的注解配置暴露代理对象,放到AopContext的ThreadLocal里去,之后就可以随时用 AopContext.currentProxy())取到代理对象。

    接下来有段重要的:

    List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    

    获取拦截器链,就是把这次相关的增强器转化成拦截器获取出来

    然后:

    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...
       invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
       // Proceed to the joinpoint through the interceptor chain.
       retVal = invocation.proceed();
    }
    

    这里就是判断拦截器链有没有东西,如果是空的就直接通过反射调用,不是空就进行else逻辑了,那else是重点了,即invocation.proceed();

    3.invocation.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是递归的终止条件,明显是根据下标进行终止的条件

    后面进行前++,又调用了

    ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    

    然而这里面是:

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

    又跑回proceed方法去了,递归。

    第二次来到的时候下标就是0了(第一次是-1,默认的),前++为1的下标的话,取出来的东西继续调用invoke发现进的是AspectJAfterThrowingAdvice的invoke了(第一次是ExposeInvocationInterceptor的invoke,记录下MethodInvocation供后面执行链获取)

    这个AspectJAfterThrowingAdvice的invoke的源码如下(不一样):

    public Object invoke(MethodInvocation mi) throws Throwable {
       try {
          return mi.proceed();
       }
       catch (Throwable ex) {
          if (shouldInvokeOnThrowing(ex)) {
             invokeAdviceMethod(getJoinPointMatch(), null, ex);
          }
          throw ex;
       }
    }
    

    继续递归,不过这次把调用链try起来了,出异常就走异常增强通知invokeAdviceMethod

    继续debug,又是递归到invoke,但这次是AfterReturningAdviceInterceptor的:

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

    提一下啊,递归是栈结构!所以我们先看到了异常调用代码和返回通知代码!

    继续递归proceed到了后置通知AspectJAfterAdvice类的invoke:

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

    看到没,后置通知类的invokeAdviceMethod调用是用的finally,所以后置通知始终执行!

    继续递归

    跳到了前置通知类MethodBeforeAdviceInterceptor的invoke

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

    注意这里不一样了!它是先调用自己再调执行链,这也就是为什么前置通知早于方法执行

    before方法执行完之后,进proceed了,递归即将结束:

    image

    所有的增强器取出来了,并执行了before 这里递归就结束了,调用目标方法:invokeJoinpoint

    然后是后置通知各种,有异常就走之前try finally那里。

    至此aop具体逻辑结束!

    总结下易翻车点:

    1.注意看自己的源码是哪个类,不然很懵逼,因为调了很多个类的同名方法invoke。

    2.注意看是递归,和递归结束条件

    3.注意invoke的实现,对于不同的增强器的逻辑是不一样的

    4.增强器那个集合是有顺序好的

  • 相关阅读:
    codeforces 701 D. As Fast As Possible(数学题)
    codeforces 807 E. Prairie Partition(贪心+思维)
    codeforces 807 D. Dynamic Problem Scoring(贪心+思维)
    codeforces 807 C. Success Rate(二分)
    Atcoder C
    Atcoder D
    hdu 3308 LCIS(线段树区间合并)
    SpringMVC学习笔记---
    Composer Yii2 不设置全局变量 归档安装 Win7
    电脑硬件扫盲--CPU 显卡
  • 原文地址:https://www.cnblogs.com/chz-blogs/p/12006222.html
Copyright © 2020-2023  润新知