AOP原理——3. AOP方法调用流程

  1. 获取拦截链
  2. 链式调用通知方法

一般情况下是DynamicAdvisedInterceptor里的intercept方法起作用。
DynamicAdvisedInterceptorCglibAopProxy的内部类

DynamicAdvisedInterceptor#intercept

		public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
			Object oldProxy = null;
			boolean setProxyContext = false;
			Object target = null;
			TargetSource targetSource = this.advised.getTargetSource();
			try {
				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);

				// 1. 获取拦截链
				// 这里获取到的拦截链是倒叙的,因为是递归调用链里通知方法(调用链里的第一个方法会回到该intercept方法),所以倒(链)倒(递归)为正。
				// 这是一种很优秀的编程思想
				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...
					// 2. 链式调用通知方法
					retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
				}
				retVal = processReturnType(proxy, target, method, retVal);
				return retVal;
			}
			finally {
				if (target != null && !targetSource.isStatic()) {
					targetSource.releaseTarget(target);
				}
				if (setProxyContext) {
					// Restore old proxy.
					AopContext.setCurrentProxy(oldProxy);
				}
			}
		}

CglibMethodInvocation#proceed

		public Object proceed() throws Throwable {
			try {
			    // proceed
				return super.proceed();
			}
			catch (RuntimeException ex) {
				throw ex;
			}
			catch (Exception ex) {
				if (ReflectionUtils.declaresException(getMethod(), ex.getClass())) {
					throw ex;
				}
				else {
					throw new UndeclaredThrowableException(ex);
				}
			}
		}

ReflectiveMethodInvocation#proceed

	public Object proceed() throws Throwable {
		// We start with an index of -1 and increment early.
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			// 当递归完后,就意味着 Before 执行完了,所以应该执行切入点了,这种编程方式值得学习
			// 为什么,下面会有答案的。
			return invokeJoinpoint();
		}

		// 根据 ++currentInterceptorIndex 从拦截链里拿
		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.
			
			// 调用通知方法,就是 MethodInterceptor 接口的 invoke 方法。通知方法的类都要继承这个接口。
			// 传入 this 控制递归,下面讲到递归的原理,以 @AfterReturning 和 @Before 为例
			// 这种控制递归的思想值得我们学习
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
	}

@AfterReturning为例,它的拦截类是AfterReturningAdviceInterceptor

public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {

	private final AfterReturningAdvice advice;


	/**
	 * Create a new AfterReturningAdviceInterceptor for the given advice.
	 * @param advice the AfterReturningAdvice to wrap
	 */
	public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {
		Assert.notNull(advice, "Advice must not be null");
		this.advice = advice;
	}


	@Override
	@Nullable
	public Object invoke(MethodInvocation mi) throws Throwable {
		// 调用 proceed 方法就递归回去了,因此不会触发下面的 afterReturning 方法,而是执行拦截链里的其他拦截器的 invoke 方法。
		Object retVal = mi.proceed();
		this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
		return retVal;
	}

}

再看 @Before,它的拦截类是MethodBeforeAdviceInterceptor

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {

	private final MethodBeforeAdvice advice;


	/**
	 * Create a new MethodBeforeAdviceInterceptor for the given advice.
	 * @param advice the MethodBeforeAdvice to wrap
	 */
	public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
		Assert.notNull(advice, "Advice must not be null");
		this.advice = advice;
	}


	@Override
	@Nullable
	public Object invoke(MethodInvocation mi) throws Throwable {
		// 先执行拦截方法。所以可以看出,递归在 Before 这里终止了,所以 Before 是第一个执行的通知方法。
		this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
		
		// Before 是拦截链里的最后一个,所以这个 proceed 方法的作用就是执行切入点了。
		return mi.proceed();
	}

}

所以proceed可以抽象地理解为执行下一个拦截器的操作。而这些拦截器又是有顺序的。
由于拦截链是反向递归调用,@Before是最后一个,所以 @Around拦截方法中在 proceedingJoinPoint.proceed()语句前面的语句可以在 @Before前执行也就好理解了。

AOP 是用的适配器模式把 Advice 变成 MethodInterceptor,这种分离与合并的思想值得学习。见我的另一篇文章: 结构型-适配器

总之 AOP 的这种设计绝了,佩服。

posted @ 2020-12-04 10:54  qianbuhan  阅读(635)  评论(0)    收藏  举报