Spring AOP 源码探索 之 方法栈及链式调用解读

文章目录

  • 方法栈及链式调用解读
    • 示例代码
    • 分析解读
      • 调用链
        • 调用链图示
        • 完整调用链接
    • JdkDynamicAopProxy.invoke
      • new ReflectiveMethodInvocation
      • ReflectiveMethodInvocation.proceed
  • 相关学习路线
    • JAVA资深架构师成长路线->开源框架解读->Spring框架源码解读

方法栈及链式调用解读

示例代码

Spring AOP 源码探索 之 示例代码

分析解读

调用链

以Debug的形式跟踪运行流程,在 calculate.add(2,4);方法调用处打断点,跟进代码。

调用链图示

Spring AOP 源码探索 之 方法栈及链式调用解读_第1张图片

完整调用链接

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类图如下:

JdkDynamicAopProxy.invoke

首先看下JDK动态切面代理的invoke方法做了什么事。
Spring AOP 源码探索 之 方法栈及链式调用解读_第2张图片
如果AOP拦截器执行链不为空 说明有AOP通知存在,
那么就根据拦截器执行链 创建一个方法调用用器 ReflectiveMethodInvocation
然后执行proceed。

new ReflectiveMethodInvocation

Spring AOP 源码探索 之 方法栈及链式调用解读_第3张图片
Spring AOP 源码探索 之 方法栈及链式调用解读_第4张图片

ReflectiveMethodInvocation.proceed

Spring AOP 源码探索 之 方法栈及链式调用解读_第5张图片
此处使用了责任链模式,实现的关键就是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注解的):
Spring AOP 源码探索 之 方法栈及链式调用解读_第6张图片
从上图我们也可以看到不同的通知其实相当于不同的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);
    }

相关学习路线

JAVA资深架构师成长路线->开源框架解读->Spring框架源码解读

你可能感兴趣的:(AOP,Spring源码,开源框架)