AOP原理——3. AOP方法调用流程
- 获取拦截链
- 链式调用通知方法
一般情况下是DynamicAdvisedInterceptor里的intercept方法起作用。
DynamicAdvisedInterceptor是CglibAopProxy的内部类
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 的这种设计绝了,佩服。

浙公网安备 33010602011771号