Spring AOP 源码探索 之 示例代码
以Debug的形式跟踪运行流程,在 calculate.add(2,4);方法调用处打断点,跟进代码。
invoke:55, MethodBeforeAdviceInterceptor (org.springframework.aop.framework.adapter)
proceed:179, ReflectiveMethodInvocation (org.springframework.aop.framework)
invoke:47, AspectJAfterAdvice (org.springframework.aop.aspectj)
proceed:179, ReflectiveMethodInvocation (org.springframework.aop.framework)
invoke:55, AfterReturningAdviceInterceptor (org.springframework.aop.framework.adapter)
proceed:179, ReflectiveMethodInvocation (org.springframework.aop.framework)
invoke:62, AspectJAfterThrowingAdvice (org.springframework.aop.aspectj)
proceed:179, ReflectiveMethodInvocation (org.springframework.aop.framework)
invoke:92, ExposeInvocationInterceptor (org.springframework.aop.interceptor)
proceed:179, ReflectiveMethodInvocation (org.springframework.aop.framework)
invoke:213, JdkDynamicAopProxy (org.springframework.aop.framework)
add:-1, $Proxy17 (com.sun.proxy)
main:13, SilasMainClass (org.silas)
ReflectiveMethodInvocation的UML类图如下:
首先看下JDK动态切面代理的invoke方法做了什么事。
如果AOP拦截器执行链不为空 说明有AOP通知存在,
那么就根据拦截器执行链 创建一个方法调用用器 ReflectiveMethodInvocation
然后执行proceed。
此处使用了责任链模式,实现的关键就是proceed方法。
org.springframework.aop.framework.ReflectiveMethodInvocation#proceed
以下是关键代码:
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
// 判断拦截器链式调用是否还有下一个拦截器需要调用
// currentInterceptorIndex初始值为 -1
// 如果执行到链条的末尾 则直接调用连接点方法 即 直接调用目标方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
// 如果当前拦截器下标等于最后一个拦截器下标,
// 那么执行 invokeJoinpoint 方法调用连接点方法
// 后面会进行分析
return invokeJoinpoint();
}
//获取集合中的 MethodInterceptor
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
//如果是InterceptorAndDynamicMethodMatcher类型
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
//这里每一次都去匹配是否适用于这个目标方法
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
//如果匹配则直接调用 MethodInterceptor的invoke方法
//注意这里传入的参数是this 我们下面看一下 ReflectiveMethodInvocation的类型
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.
//说明是适用于此目标方法的 直接调用 MethodInterceptor的invoke方法 传入this即ReflectiveMethodInvocation实例
//传入this进入 这样就可以形成一个调用的链条了
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
proceed()这个方法中看到了AOP对于目标方法的一个拦截的过程,其中很重要的一个点是调用MethodInterceptor的invoke方法。我们先看一下MethodInterceptor的主要UML类图(由于在开发中使用AspectJ注解的方式越来越多,并且spring官方也推荐用注解的形式,所以这里说的基本上都是基于AspectJ注解的):
从上图我们也可以看到不同的通知其实相当于不同的MethodInterceptor类型。像前置通知会交给:MethodBeforeAdviceInterceptor来进行处理,后置通知是由AspectJAfterAdvice来处理的,环绕通知是由AspectJAroundAdvice来处理的。
先说一下前置通知:
MethodBeforeAdviceInterceptor
//实现了MethodInterceptor接口
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
//这个对象的获取参考这个方法org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvice
//在之前的文章中有说过 不再描述
//这个MethodBeforeAdvice是AspectJMethodBeforeAdvice实例
private MethodBeforeAdvice advice;
public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
//这里就会执行 前置通知的逻辑 这里的advice是 AspectJMethodBeforeAdvice
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
//这里传入的MethodInvocation是ReflectiveMethodInvocation对象,即前面说的 传入this
//相当于ReflectiveMethodInvocation.proceed() 递归调用。
return mi.proceed();
}
}
AspectJMethodBeforeAdvice#beforet和代码如下:
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
//这里传进来的目标对象、目标参数、目标方法都没有用到
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
JoinPointMatch 代码
protected JoinPointMatch getJoinPointMatch() {
MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
if (!(mi instanceof ProxyMethodInvocation)) {
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
}
//这里主要是获取 JoinPointMatch
return getJoinPointMatch((ProxyMethodInvocation) mi);
}