SpringAop七、AOP运行时

之前说过jdk的动态代理运行时就是关注对应的InvocationHandler实现,这里就是JdkDynamicAopProxy类,运行时看invoke方法

@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   MethodInvocation invocation;
   Object oldProxy = null;
   boolean setProxyContext = false;

   TargetSource targetSource = this.advised.targetSource;
   Object target = null;

   try {
      if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
         // The target does not implement the equals(Object) method itself.
         return equals(args[0]);
      }
      else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
         // The target does not implement the hashCode() method itself.
         return hashCode();
      }
      else if (method.getDeclaringClass() == DecoratingProxy.class) {
         // There is only getDecoratedClass() declared -> dispatch to proxy config.
         return AopProxyUtils.ultimateTargetClass(this.advised);
      }
      else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
            method.getDeclaringClass().isAssignableFrom(Advised.class)) {
         // Service invocations on ProxyConfig with the proxy config...
         return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
      }

      Object retVal;

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

      // Get as late as possible to minimize the time we "own" the target,
      // in case it comes from a pool.
      target = targetSource.getTarget();
      Class<?> targetClass = (target != null ? target.getClass() : null);

      // Get the interception chain for this method.
      // 获取所有的通知
      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.
         // 没有通知器的情况下,method.invoke
         Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
         retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
      }
      else {
         // We need to create a method invocation...
         // invocation 包裹了调用过程,除了目标方法,还有通过AOP实现的切面方法
         // 主要是这个chain,是一个拦截器链,invocation.proceed()时根据具体情况选择各种切面方式
         invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
         // Proceed to the joinpoint through the interceptor chain.
         retVal = invocation.proceed();
      }

      // Massage return value if necessary.
      Class<?> returnType = method.getReturnType();
      if (retVal != null && retVal == target &&
            returnType != Object.class && returnType.isInstance(proxy) &&
            !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
         // Special case: it returned "this" and the return type of the method
         // is type-compatible. Note that we can't help if the target sets
         // a reference to itself in another returned object.
         retVal = proxy;
      }
      else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
         throw new AopInvocationException(
               "Null return value from advice does not match primitive return type for: " + method);
      }
      return retVal;
   }
   finally {
      if (target != null && !targetSource.isStatic()) {
         // Must have come from TargetSource.
         targetSource.releaseTarget(target);
      }
      if (setProxyContext) {
         // Restore old proxy.
         AopContext.setCurrentProxy(oldProxy);
      }
   }
}

蛮长的,不过大部分代码都不是重点。前面就是做一些判断,对于equals、hashCode这样的方法做了通用处理,不需要代理的方法直接method.invoke.
List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); 这一行,拿到的通知器集合就有一部分映射成了拦截器

// We need to create a method invocation...
// invocation 包裹了调用过程,除了目标方法,还有通过AOP实现的切面方法
// 主要是这个chain,invocation.proceed()时根据具体情况选择各种切面方式
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();

这部分是重点
先构造一个invocation运行时对象,里面带入了chain,然后执行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) {
      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;
      Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
      if (dm.methodMatcher.matches(this.method, 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);
   }
}

第一部分,当链调用到最后的时候执行invokeJoinpoint(),这里就是原始的method.invoke
获得advisor是通过index获取,每次获取完index都会++, 下面的advisor.invoke(this)会传当前对象进去。 也就是说每个advisor里面只要调用了proceed方法就都会回来这里。 实际上就是这么做的。 这样就形成了一个链式调用。

下面详细看一下每个advisor里的实现。 mi.proceed 在最内层就可以理解为调用原方法

  • MethodBeforeAdviceInterceptor
// 调用方法前通知方法,在调用方法。 before方法实际上还是aspectJAdviceMethod的invoke
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
   this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
   return mi.proceed();
}

先调通知方法,再proceed继续往下走

  • AspectJAfterAdvice
// 就是包了层finally, 里面还是aspectJAdviceMethod.invoke
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
   try {
      return mi.proceed();
   }
   finally {
      invokeAdviceMethod(getJoinPointMatch(), null, null);
   }
}

包了层finally,里面是通知方法,就是说最后不管怎么样都会来执行一下这个通知方法

  • AfterReturningAdviceInterceptor
//返回后加了方法,内部就是调用invokeAdviceMethod,最终还是aspectJAdviceMethod的invoke
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
   Object retVal = mi.proceed();
   this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
   return retVal;
}

先执行原方法,然后加入后置通知方法。当然前面如果异常了就没这个了。

  • AspectJAfterThrowingAdvice
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
   // 就是外面包了一层异常捕获,捕获到异常执行invokeAdviceMethod
   // 里面就是aspectJAdviceMethod的invoke调用
   try {
      return mi.proceed();
   }
   catch (Throwable ex) {
      if (shouldInvokeOnThrowing(ex)) {
         invokeAdviceMethod(getJoinPointMatch(), null, ex);
      }
      throw ex;
   }
}

就是包了层异常捕获,在获取异常后执行通知方法。当然没异常就不会进去了

  • AspectJAroundAdvice
/这个会先把MethodInvocation封装成ProceedingJoinPoint,然后在调用的时候当做参数传进去。
// mi.process是调用用户的方法,这里把mi包进去,然后调用通知方法,当通知方法里调用pjp.process时就是调用了mi的
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
   if (!(mi instanceof ProxyMethodInvocation)) {
      throw new IllegalStateException(&quot;MethodInvocation is not a Spring ProxyMethodInvocation: &quot; + mi);
   }
   ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
   ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
   JoinPointMatch jpm = getJoinPointMatch(pmi);
   return invokeAdviceMethod(pjp, jpm, null, null);
}

这里包装了一下参数,然后执行通知方法,这也是为什么我们定义的通知方法参数中需要ProceedingJoinPoint参数的原因。 而调用joinPoint.proceed()时,实际上就是上面的mi.proceed(), 就又回到了链中。

至此jdk动态代理运行时完了。 cglib的实现和这个差不多,最终每个advisor调用也是上面这部分代码。

总结一下

  • 5种通知器,对应5种处理方法。
  • 顺序,注意顺序。
  • 原方法调用时是method.invoke,即原方法的反射调用,当方法中调用其他方法时,是不进入AOP切面的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值