Spring AOP原理-代理对象的底层执行逻辑

从 0 开始深入学习 Spring 专栏目录总览

代理对象已经创建好了,接下来就到了正常的业务代码执行了。经过 AOP 的增强后,获取到目标对象的代理对象执行方法时,就会先执行 AOP 增强中的增强器逻辑。下面咱继续以 com.linkedbear.spring.aop.b_aspectj.AnnotationAspectJApplication 中的代码来测试,执行 financeService.addMoney 方法和 orderService.getOrderById 方法的底层逻辑。

1. FinanceService#addMoney

将断点打在 addMoney 方法的调用上,Debug 进入时,会发现它先来到了 CglibAopProxy 的内部类 DynamicAdvisedInterceptor 中:(下面的源码有点长,小册把不太重要的注释都删掉,只留下重要的几个环节,小伙伴们注意留意)

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 {
        // 如果有在@EnableAspectJAutoProxy注解上配置exposeProxy属性为true,
        // 则会把当前代理对象放入AOP上下文中
        if (this.advised.exposeProxy) {
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }
        // 从TargetSource中取出目标对象
        target = targetSource.getTarget();
        Class<?> targetClass = (target != null ? target.getClass() : null);
        // 根据当前执行的方法,获取要执行的增强器,并以列表返回(链的思想)
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
        Object retVal;
        
        // 如果没有要执行的增强器,则直接执行目标方法
        if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            retVal = methodProxy.invoke(target, argsToUse);
        }
        else {
            // 否则,构造增强器链,执行增强器的逻辑
            retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
        }
        retVal = processReturnType(proxy, target, method, retVal);
        return retVal;
    } // finally ......
}

整个流程下来,核心步骤就两步:获取增强器链、执行增强器。同时这里也发现了之前咱讲过的一些小细节:exposeProxy 的实现、TargetSource 的使用等等。不过我们最需要关注的还是这两个核心部分,咱分别来研究。

1.1 getInterceptorsAndDynamicInterceptionAdvice

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
    MethodCacheKey cacheKey = new MethodCacheKey(method);
    List<Object> cached = this.methodCache.get(cacheKey);
    if (cached == null) {
        // 核心逻辑
        cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
                this, method, targetClass);
        this.methodCache.put(cacheKey, cached);
    }
    return cached;
}

很明显又是缓存的设计,第一次调用完成后,以后就直接从缓存中读了,不需要多次获取和解析。刨去这个不看,核心的方法还是 if 结构中的方法了,咱继续往里进。不过里面的逻辑有点长,咱拆开分段研究:

1.1.1 前置准备

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
        Advised config, Method method, @Nullable Class<?> targetClass) {
    // 增强器适配器的注册器,它会根据增强器来解析,返回拦截器数组
    AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
    Advisor[] advisors = config.getAdvisors();
    List<Object> interceptorList = new ArrayList<>(advisors.length);
    Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
    Boolean hasIntroductions = null;
    // ......

在循环处理增强器之前,这里先进行了一些基本的前置处理,这里它初始化了一个 AdvisorAdapterRegistry ,意为增强器适配器的注册器,它的主要作用是将 AspectJ 类型的增强器,转换为 MethodInterceptor ( AOP 联盟的那个 MethodInterceptor )并返回。此举的目的,会在接下来的 CglibMethodInvocation 中得以体现,咱这里先有个印象即可。

Debug 到此处,发现这里面有 3 个增强器的适配器,虽然没法 toString ,但看这个名也就知道,这大概就是 Logger 那个切面类中的那几个方法。

Spring AOP原理-代理对象的底层执行逻辑

1.1.2 匹配增强器

这部分开始循环匹配增强器了:

    // ......
    for (Advisor advisor : advisors) {
        if (advisor instanceof PointcutAdvisor) {
            // 此处拿到的就是AspectJ形式的通知方法封装
            PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
            if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                // 根据通知方法上的切入点表达式,判断是否可以匹配当前要执行的目标对象所属类
                MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                boolean match;
                // 引介匹配
                if (mm instanceof IntroductionAwareMethodMatcher) {
                    if (hasIntroductions == null) {
                        hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
                    }
                    match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
                }
                else {
                    // 方法匹配
                    match = mm.matches(method, actualClass);
                }
                // ......

这部分的匹配逻辑也不难,它会把上面取出来的增强器依次与当前正在调用的目标对象做匹配,匹配的方式与之前一样,都是借助 MethodMatcher 进行。

Debug 可以发现此处把 Logger 中声明的 5 个通知方法,以及 SpringFramework 内置的那个增强器,一起都收集到了:

Spring AOP原理-代理对象的底层执行逻辑

1.1.3 匹配后的处理

匹配到增强器之后,接下来就是决定如何封装为 MethodInterceptor 了:

                // ......
                if (match) {
                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                    // runtime的概念
                    if (mm.isRuntime()) {
                        for (MethodInterceptor interceptor : interceptors) {
                            interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                        }
                    } else {
                        interceptorList.addAll(Arrays.asList(interceptors));
                    }
                }
            }
        }
        // ......

这部分本身的添加并不难,不过这里面有一个 runtime 的概念,想必小伙伴们会比较懵,这里咱简单解释一下。

通常情况下,MethodMatcher 都是静态的匹配器,但 Spring 在此处做了一个设计,如果 MethodMatcher 被设置为动态的匹配器,则每次调用匹配方法时,可以提前拿到方法调用的参数值列表。说起来有点难理解,咱先看两个方法的签名:

boolean matches(Method method, Class<?> targetClass);

boolean matches(Method method, Class<?> targetClass, Object... args);

小册这样解释一下,你们都就立马明白了:静态匹配器只会做匹配,而动态的匹配器可以提前拿到方法调用的参数值列表(注意是参数值)。

1.1.4 其他增强器的处理

        // ......
        else if (advisor instanceof IntroductionAdvisor) {
            IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
            if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
                Interceptor[] interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        }
        else {
            Interceptor[] interceptors = registry.getInterceptors(advisor);
            interceptorList.addAll(Arrays.asList(interceptors));
        }
    }

    return interceptorList;
}

在最下面,就是引介增强器,以及其它类型的增强器的处理了,这里咱一般都碰不到,AspectJ 风格的声明都是走上面的 PointcutAdvisor 判断逻辑,所以咱这里就不细展开了。

经过这个方法的处理之后,当前目标对象要执行的方法就都筛选出来了,接下来就是构建方法执行器了。

1.2 CglibMethodInvocation

下面是构造的 CglibMethodInvocation ,执行 proceed 方法了,咱先看看这个 CglibMethodInvocation 是个啥:

private static class CglibMethodInvocation extends ReflectiveMethodInvocation
public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable
public interface ProxyMethodInvocation extends MethodInvocation

得了,果然还是回到 AOP 联盟定义的那个 MethodInvocation 了,那咱就知道上面的那个适配的设计了,大家都是 MethodInvocation ,那就都好说了。

接下来,咱执行 proceed 方法,而在 CglibMethodInvocation 中,它只是单纯的调用父类的 proceed 方法:

public Object proceed() throws Throwable {
    try {
        return super.proceed();
    } // catch ......
}

那往上调用,那就来到 ReflectiveMethodInvocation 类中了。

接下来的调用过程可能会很绕,小册尝试用过程的方式记录每一步的执行动作和逻辑,方便小伙伴们体会这里面的高深设计。

1.2.0 方法概览

先大概看一下 proceed 方法的设计吧,

protected final List<?> interceptorsAndDynamicMethodMatchers;
private int currentInterceptorIndex = -1;

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) {
        // 此处是动态匹配器构造的特殊逻辑
        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 {
            return proceed();
        }
    }
    else {
        // 此处会调用增强器的逻辑
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
}

这里先解释一波动态匹配器的逻辑,看中间的 if 部分,如果 MethodMatcher 有被封装为动态匹配器,则这里会继续匹配,如果动态匹配器在匹配到方法调用的参数值列表发现匹配不上,则这个增强器不会执行。

其余的部分,就看接下来的执行逻辑咯,小伙伴们不要被小册搞晕哦。

1.2.1 执行proceed方法

public Object proceed() throws Throwable {
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return invokeJoinpoint();
    }

此时的 currentInterceptorIndex 下标值为 -1 :

Spring AOP原理-代理对象的底层执行逻辑

计算值:-1 ≠ 3 - 1,则不进入 invokeJoinpoint 方法,继续往下走。

1.2.2 下标值++

接下来,执行下面的 this.interceptorsAndDynamicMethodMatchers.get 动作,此时 this.currentInterceptorIndex 执行了一次自增操作:

    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return invokeJoinpoint();
    }

    Object interceptorOrInterceptionAdvice =
            this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {

此时 currentInterceptorIndex 值为 0 。

1.2.3 执行第一个增强器

既然获取到了增强器对应的拦截器,那就执行它:

public Object invoke(MethodInvocation mi) throws Throwable {
    MethodInvocation oldInvocation = invocation.get();
    invocation.set(mi);
    try {
        return mi.proceed();
    }
    finally {
        invocation.set(oldInvocation);
    }
}

又看到这个 invoke 方法了,咱已经挺熟悉了,下一步肯定是继续执行 proceed 方法嘛。

1.2.4 继续执行proceed方法

接下来执行 proceed 方法,会发现它又回到上面的 1.2.1 步了,只不过此时的 currentInterceptorIndex 值不再是 -1 ,而是 0 。

Spring AOP原理-代理对象的底层执行逻辑

计算值:0 ≠ 3 - 1,则不进入 invokeJoinpoint 方法,继续往下走。

1.2.5 进入AspectJAroundAdvice中

那既然计算结果不等,那就继续执行增强器逻辑嘛,由于接下来要执行的是一个环绕通知,咱来到 AspectJAroundAdvice 的 invoke 方法中:

public Object invoke(MethodInvocation mi) throws Throwable {
    if (!(mi instanceof ProxyMethodInvocation)) {
        throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
    }
    ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
    ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
    JoinPointMatch jpm = getJoinPointMatch(pmi);
    return invokeAdviceMethod(pjp, jpm, null, null);
}

前面的获取都是很基本的了,最下面的 invokeAdviceMethod 才是关键:

protected Object invokeAdviceMethod(JoinPoint jp, @Nullable JoinPointMatch jpMatch,
        @Nullable Object returnValue, @Nullable Throwable t) throws Throwable {
    return invokeAdviceMethodWithGivenArgs(argBinding(jp, jpMatch, returnValue, t));
}

protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
    Object[] actualArgs = args;
    if (this.aspectJAdviceMethod.getParameterCount() == 0) {
        actualArgs = null;
    }
    try {
        ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
        return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
    } // catch ......
}

合着折腾到最后,还是个反射执行目标对象的方法。。。

1.2.6 进入到Logger中

因为是环绕通知嘛,那就理所应当的进入到 Logger 中了:

@Around("execution(public * com.linkedbear.spring.aop.b_aspectj.service.FinanceService.addMoney(..))")
public Object aroundPrint(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("Logger aroundPrint before run ......");
    try {
        Object retVal = joinPoint.proceed();
        System.out.println("Logger aroundPrint afterReturning run ......");
        return retVal;
    } // catch finally ......
}

执行了前置通知打印后,接下来的 joinPoint.proceed 方法的执行,想必不用小册解释,小伙伴们也能想得到了吧。

1.2.7 继续执行proceed方法

想是想到了,但这个中间还有个小插曲。。。proceed 方法的执行,肯定是走的 ProceedingJoinPoint 的 proceed 方法呀,不是上面 ReflectiveMethodInvocation 的:

public Object proceed() throws Throwable {
    return this.methodInvocation.invocableClone().proceed();
}

哎,这里的 proceed 方法,才是上面咱执行那些 proceed 方法,此时 currentInterceptorIndex 的值为 1 :

Spring AOP原理-代理对象的底层执行逻辑

然后,又是同样的获取、自增、执行。。。

1.2.8 进入MethodBeforeAdviceInterceptor中

第三个通知方法的执行,是那个前置通知,它会来到 MethodBeforeAdviceInterceptor 中:

public Object invoke(MethodInvocation mi) throws Throwable {
    this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
    return mi.proceed();
}

可以发现还蛮简单的,它就是把前置通知的方法执行一下,然后继续执行 MethodInvocation 的 proceed 方法了。

1.2.9 执行目标对象方法

接下来,又回到 proceed 方法,此时 currentInterceptorIndex 的值为 2 :

计算得 2 = 3 - 1 ,终于相等了,那就可以执行目标方法了。

1.2.10 流程小结

好了,经过这个流程之后,咱终于走完这个全程,由此我们可以得出算法逻辑:

利用一个全局索引值,决定每次执行的拦截器,当所有拦截器都执行完时,索引值刚好等于 size() - 1,此时就可以执行真正的目标方法了 。

最后用一张图来更好地理解这段逻辑:

Spring AOP原理-代理对象的底层执行逻辑

2. OrderService#getOrderById

咱继续研究 jdk 动态代理的执行。将断点打在 getOrderById 方法的调用上,Debug 进入时它肯定就不跟上面的 Cglib 动态代理一样了,它进入的是 JdkDynamicAopProxy 中。不过由于这里面的 invoke 方法实在是有点长,小册在这里只截取关键部分:

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

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

    try {
        // equals方法不代理
        if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
            // The target does not implement the equals(Object) method itself.
            return equals(args[0]);
        }
        // hashCode方法不代理
        else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
            // The target does not implement the hashCode() method itself.
            return hashCode();
        }
        // 方法来自于DecoratingProxy接口的,也不代理
        else if (method.getDeclaringClass() == DecoratingProxy.class) {
            // There is only getDecoratedClass() declared -> dispatch to proxy config.
            return AopProxyUtils.ultimateTargetClass(this.advised);
        }
        // 目标对象本身就是实现了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) {
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }

        target = targetSource.getTarget();
        Class<?> targetClass = (target != null ? target.getClass() : null);

        // 根据当前执行的方法,获取要执行的增强器,并以列表返回(链的思想)
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
        if (chain.isEmpty()) {
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
        }
        else {
            MethodInvocation invocation =
                    new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
            // 构造增强器链,执行增强器的逻辑
            retVal = invocation.proceed();
        }
        // 返回值的处理 ......
        return retVal;
    } // finally ......
}

先看下面的部分,是不是跟上面 CglibAopProxy 完全一致?所以 这两者其实在底层实现中都是一样的,包括这里它创建的直接就是 ReflectiveMethodInvocation ,与上面咱看到的那个家伙是同一个。

所以这个逻辑也是一模一样的吧,具体流程这个就留给小伙伴当课后作业了,小册只在这里附一张类似的流程图啦:

Spring AOP原理-代理对象的底层执行逻辑

3. Aspect中的四种通知在源码中的实现

最后,咱对 AspectJ 中提到的四种声明式的通知,它的底层实现有一个简单的了解,前面咱看过环绕通知了,所以这个咱就不列出来了。

3.1 @Before

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
	private MethodBeforeAdvice advice;

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
		return mi.proceed();
	}
}

先执行前置通知,再执行目标方法。

3.2 @After

public class AspectJAfterAdvice extends AbstractAspectJAdvice
		implements MethodInterceptor, AfterAdvice, Serializable {

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		try {
			return mi.proceed();
		}
		finally {
			invokeAdviceMethod(getJoinPointMatch(), null, null);
		}
	}
}

执行目标方法后,在 finally 中执行后置方法(由此也说明了它的通知时机更靠后)。

3.3 @AfterReturning

public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {
	private final AfterReturningAdvice advice;

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		Object retVal = mi.proceed();
		this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
		return retVal;
	}
}

返回值后置处理中不设置 try-catch 块,说明不出现任何异常时才会触发该后置通知。

3.4 @AfterThrowing

public class AspectJAfterThrowingAdvice extends AbstractAspectJAdvice
		implements MethodInterceptor, AfterAdvice, Serializable {

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		try {
			return mi.proceed();
		}
		catch (Throwable ex) {
			if (shouldInvokeOnThrowing(ex)) {
				invokeAdviceMethod(getJoinPointMatch(), null, ex);
			}
			throw ex;
		}
	}
}

出现异常时,进入该后置通知,因为设置了 try-catch ,所以这里 catch 中根据是否标注了异常通知,进行相应的后置处理。

代理对象已经创建好了,接下来就到了正常的业务代码执行了。经过 AOP 的增强后,获取到目标对象的代理对象执行方法时,就会先执行 AOP 增强中的增强器逻辑。下面咱继续以 com.linkedbear.spring.aop.b_aspectj.AnnotationAspectJApplication 中的代码来测试,执行 financeService.addMoney 方法和 orderService.getOrderById 方法的底层逻辑。

1. FinanceService#addMoney

将断点打在 addMoney 方法的调用上,Debug 进入时,会发现它先来到了 CglibAopProxy 的内部类 DynamicAdvisedInterceptor 中:(下面的源码有点长,小册把不太重要的注释都删掉,只留下重要的几个环节,小伙伴们注意留意)

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 {
        // 如果有在@EnableAspectJAutoProxy注解上配置exposeProxy属性为true,
        // 则会把当前代理对象放入AOP上下文中
        if (this.advised.exposeProxy) {
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }
        // 从TargetSource中取出目标对象
        target = targetSource.getTarget();
        Class<?> targetClass = (target != null ? target.getClass() : null);
        // 根据当前执行的方法,获取要执行的增强器,并以列表返回(链的思想)
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
        Object retVal;
        
        // 如果没有要执行的增强器,则直接执行目标方法
        if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            retVal = methodProxy.invoke(target, argsToUse);
        }
        else {
            // 否则,构造增强器链,执行增强器的逻辑
            retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
        }
        retVal = processReturnType(proxy, target, method, retVal);
        return retVal;
    } // finally ......
}

整个流程下来,核心步骤就两步:获取增强器链、执行增强器。同时这里也发现了之前咱讲过的一些小细节:exposeProxy 的实现、TargetSource 的使用等等。不过我们最需要关注的还是这两个核心部分,咱分别来研究。

1.1 getInterceptorsAndDynamicInterceptionAdvice

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
    MethodCacheKey cacheKey = new MethodCacheKey(method);
    List<Object> cached = this.methodCache.get(cacheKey);
    if (cached == null) {
        // 核心逻辑
        cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
                this, method, targetClass);
        this.methodCache.put(cacheKey, cached);
    }
    return cached;
}

很明显又是缓存的设计,第一次调用完成后,以后就直接从缓存中读了,不需要多次获取和解析。刨去这个不看,核心的方法还是 if 结构中的方法了,咱继续往里进。不过里面的逻辑有点长,咱拆开分段研究:

1.1.1 前置准备

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
        Advised config, Method method, @Nullable Class<?> targetClass) {
    // 增强器适配器的注册器,它会根据增强器来解析,返回拦截器数组
    AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
    Advisor[] advisors = config.getAdvisors();
    List<Object> interceptorList = new ArrayList<>(advisors.length);
    Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
    Boolean hasIntroductions = null;
    // ......

在循环处理增强器之前,这里先进行了一些基本的前置处理,这里它初始化了一个 AdvisorAdapterRegistry ,意为增强器适配器的注册器,它的主要作用是将 AspectJ 类型的增强器,转换为 MethodInterceptor ( AOP 联盟的那个 MethodInterceptor )并返回。此举的目的,会在接下来的 CglibMethodInvocation 中得以体现,咱这里先有个印象即可。

Debug 到此处,发现这里面有 3 个增强器的适配器,虽然没法 toString ,但看这个名也就知道,这大概就是 Logger 那个切面类中的那几个方法。

Spring AOP原理-代理对象的底层执行逻辑

1.1.2 匹配增强器

这部分开始循环匹配增强器了:

    // ......
    for (Advisor advisor : advisors) {
        if (advisor instanceof PointcutAdvisor) {
            // 此处拿到的就是AspectJ形式的通知方法封装
            PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
            if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                // 根据通知方法上的切入点表达式,判断是否可以匹配当前要执行的目标对象所属类
                MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                boolean match;
                // 引介匹配
                if (mm instanceof IntroductionAwareMethodMatcher) {
                    if (hasIntroductions == null) {
                        hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
                    }
                    match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
                }
                else {
                    // 方法匹配
                    match = mm.matches(method, actualClass);
                }
                // ......

这部分的匹配逻辑也不难,它会把上面取出来的增强器依次与当前正在调用的目标对象做匹配,匹配的方式与之前一样,都是借助 MethodMatcher 进行。

Debug 可以发现此处把 Logger 中声明的 5 个通知方法,以及 SpringFramework 内置的那个增强器,一起都收集到了:

Spring AOP原理-代理对象的底层执行逻辑

1.1.3 匹配后的处理

匹配到增强器之后,接下来就是决定如何封装为 MethodInterceptor 了:

                // ......
                if (match) {
                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                    // runtime的概念
                    if (mm.isRuntime()) {
                        for (MethodInterceptor interceptor : interceptors) {
                            interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                        }
                    } else {
                        interceptorList.addAll(Arrays.asList(interceptors));
                    }
                }
            }
        }
        // ......

这部分本身的添加并不难,不过这里面有一个 runtime 的概念,想必小伙伴们会比较懵,这里咱简单解释一下。

通常情况下,MethodMatcher 都是静态的匹配器,但 Spring 在此处做了一个设计,如果 MethodMatcher 被设置为动态的匹配器,则每次调用匹配方法时,可以提前拿到方法调用的参数值列表。说起来有点难理解,咱先看两个方法的签名:

boolean matches(Method method, Class<?> targetClass);

boolean matches(Method method, Class<?> targetClass, Object... args);

小册这样解释一下,你们都就立马明白了:静态匹配器只会做匹配,而动态的匹配器可以提前拿到方法调用的参数值列表(注意是参数值)。

1.1.4 其他增强器的处理

        // ......
        else if (advisor instanceof IntroductionAdvisor) {
            IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
            if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
                Interceptor[] interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        }
        else {
            Interceptor[] interceptors = registry.getInterceptors(advisor);
            interceptorList.addAll(Arrays.asList(interceptors));
        }
    }

    return interceptorList;
}

在最下面,就是引介增强器,以及其它类型的增强器的处理了,这里咱一般都碰不到,AspectJ 风格的声明都是走上面的 PointcutAdvisor 判断逻辑,所以咱这里就不细展开了。

经过这个方法的处理之后,当前目标对象要执行的方法就都筛选出来了,接下来就是构建方法执行器了。

1.2 CglibMethodInvocation

下面是构造的 CglibMethodInvocation ,执行 proceed 方法了,咱先看看这个 CglibMethodInvocation 是个啥:

private static class CglibMethodInvocation extends ReflectiveMethodInvocation
public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable
public interface ProxyMethodInvocation extends MethodInvocation

得了,果然还是回到 AOP 联盟定义的那个 MethodInvocation 了,那咱就知道上面的那个适配的设计了,大家都是 MethodInvocation ,那就都好说了。

接下来,咱执行 proceed 方法,而在 CglibMethodInvocation 中,它只是单纯的调用父类的 proceed 方法:

public Object proceed() throws Throwable {
    try {
        return super.proceed();
    } // catch ......
}

那往上调用,那就来到 ReflectiveMethodInvocation 类中了。

接下来的调用过程可能会很绕,小册尝试用过程的方式记录每一步的执行动作和逻辑,方便小伙伴们体会这里面的高深设计。

1.2.0 方法概览

先大概看一下 proceed 方法的设计吧,

protected final List<?> interceptorsAndDynamicMethodMatchers;
private int currentInterceptorIndex = -1;

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) {
        // 此处是动态匹配器构造的特殊逻辑
        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 {
            return proceed();
        }
    }
    else {
        // 此处会调用增强器的逻辑
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
}

这里先解释一波动态匹配器的逻辑,看中间的 if 部分,如果 MethodMatcher 有被封装为动态匹配器,则这里会继续匹配,如果动态匹配器在匹配到方法调用的参数值列表发现匹配不上,则这个增强器不会执行。

其余的部分,就看接下来的执行逻辑咯,小伙伴们不要被小册搞晕哦。

1.2.1 执行proceed方法

public Object proceed() throws Throwable {
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return invokeJoinpoint();
    }

此时的 currentInterceptorIndex 下标值为 -1 :

Spring AOP原理-代理对象的底层执行逻辑

计算值:-1 ≠ 3 - 1,则不进入 invokeJoinpoint 方法,继续往下走。

1.2.2 下标值++

接下来,执行下面的 this.interceptorsAndDynamicMethodMatchers.get 动作,此时 this.currentInterceptorIndex 执行了一次自增操作:

    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return invokeJoinpoint();
    }

    Object interceptorOrInterceptionAdvice =
            this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {

此时 currentInterceptorIndex 值为 0 。

1.2.3 执行第一个增强器

既然获取到了增强器对应的拦截器,那就执行它:

public Object invoke(MethodInvocation mi) throws Throwable {
    MethodInvocation oldInvocation = invocation.get();
    invocation.set(mi);
    try {
        return mi.proceed();
    }
    finally {
        invocation.set(oldInvocation);
    }
}

又看到这个 invoke 方法了,咱已经挺熟悉了,下一步肯定是继续执行 proceed 方法嘛。

1.2.4 继续执行proceed方法

接下来执行 proceed 方法,会发现它又回到上面的 1.2.1 步了,只不过此时的 currentInterceptorIndex 值不再是 -1 ,而是 0 。

Spring AOP原理-代理对象的底层执行逻辑

计算值:0 ≠ 3 - 1,则不进入 invokeJoinpoint 方法,继续往下走。

1.2.5 进入AspectJAroundAdvice中

那既然计算结果不等,那就继续执行增强器逻辑嘛,由于接下来要执行的是一个环绕通知,咱来到 AspectJAroundAdvice 的 invoke 方法中:

public Object invoke(MethodInvocation mi) throws Throwable {
    if (!(mi instanceof ProxyMethodInvocation)) {
        throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
    }
    ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
    ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
    JoinPointMatch jpm = getJoinPointMatch(pmi);
    return invokeAdviceMethod(pjp, jpm, null, null);
}

前面的获取都是很基本的了,最下面的 invokeAdviceMethod 才是关键:

protected Object invokeAdviceMethod(JoinPoint jp, @Nullable JoinPointMatch jpMatch,
        @Nullable Object returnValue, @Nullable Throwable t) throws Throwable {
    return invokeAdviceMethodWithGivenArgs(argBinding(jp, jpMatch, returnValue, t));
}

protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
    Object[] actualArgs = args;
    if (this.aspectJAdviceMethod.getParameterCount() == 0) {
        actualArgs = null;
    }
    try {
        ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
        return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
    } // catch ......
}

合着折腾到最后,还是个反射执行目标对象的方法。。。

1.2.6 进入到Logger中

因为是环绕通知嘛,那就理所应当的进入到 Logger 中了:

@Around("execution(public * com.linkedbear.spring.aop.b_aspectj.service.FinanceService.addMoney(..))")
public Object aroundPrint(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("Logger aroundPrint before run ......");
    try {
        Object retVal = joinPoint.proceed();
        System.out.println("Logger aroundPrint afterReturning run ......");
        return retVal;
    } // catch finally ......
}

执行了前置通知打印后,接下来的 joinPoint.proceed 方法的执行,想必不用小册解释,小伙伴们也能想得到了吧。

1.2.7 继续执行proceed方法

想是想到了,但这个中间还有个小插曲。。。proceed 方法的执行,肯定是走的 ProceedingJoinPoint 的 proceed 方法呀,不是上面 ReflectiveMethodInvocation 的:

public Object proceed() throws Throwable {
    return this.methodInvocation.invocableClone().proceed();
}

哎,这里的 proceed 方法,才是上面咱执行那些 proceed 方法,此时 currentInterceptorIndex 的值为 1 :

Spring AOP原理-代理对象的底层执行逻辑

然后,又是同样的获取、自增、执行。。。

1.2.8 进入MethodBeforeAdviceInterceptor中

第三个通知方法的执行,是那个前置通知,它会来到 MethodBeforeAdviceInterceptor 中:

public Object invoke(MethodInvocation mi) throws Throwable {
    this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
    return mi.proceed();
}

可以发现还蛮简单的,它就是把前置通知的方法执行一下,然后继续执行 MethodInvocation 的 proceed 方法了。

1.2.9 执行目标对象方法

接下来,又回到 proceed 方法,此时 currentInterceptorIndex 的值为 2 :

计算得 2 = 3 - 1 ,终于相等了,那就可以执行目标方法了。

1.2.10 流程小结

好了,经过这个流程之后,咱终于走完这个全程,由此我们可以得出算法逻辑:

利用一个全局索引值,决定每次执行的拦截器,当所有拦截器都执行完时,索引值刚好等于 size() - 1,此时就可以执行真正的目标方法了 。

最后用一张图来更好地理解这段逻辑:

Spring AOP原理-代理对象的底层执行逻辑

2. OrderService#getOrderById

咱继续研究 jdk 动态代理的执行。将断点打在 getOrderById 方法的调用上,Debug 进入时它肯定就不跟上面的 Cglib 动态代理一样了,它进入的是 JdkDynamicAopProxy 中。不过由于这里面的 invoke 方法实在是有点长,小册在这里只截取关键部分:

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

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

    try {
        // equals方法不代理
        if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
            // The target does not implement the equals(Object) method itself.
            return equals(args[0]);
        }
        // hashCode方法不代理
        else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
            // The target does not implement the hashCode() method itself.
            return hashCode();
        }
        // 方法来自于DecoratingProxy接口的,也不代理
        else if (method.getDeclaringClass() == DecoratingProxy.class) {
            // There is only getDecoratedClass() declared -> dispatch to proxy config.
            return AopProxyUtils.ultimateTargetClass(this.advised);
        }
        // 目标对象本身就是实现了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) {
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }

        target = targetSource.getTarget();
        Class<?> targetClass = (target != null ? target.getClass() : null);

        // 根据当前执行的方法,获取要执行的增强器,并以列表返回(链的思想)
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
        if (chain.isEmpty()) {
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
        }
        else {
            MethodInvocation invocation =
                    new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
            // 构造增强器链,执行增强器的逻辑
            retVal = invocation.proceed();
        }
        // 返回值的处理 ......
        return retVal;
    } // finally ......
}

先看下面的部分,是不是跟上面 CglibAopProxy 完全一致?所以 这两者其实在底层实现中都是一样的,包括这里它创建的直接就是 ReflectiveMethodInvocation ,与上面咱看到的那个家伙是同一个。

所以这个逻辑也是一模一样的吧,具体流程这个就留给小伙伴当课后作业了,小册只在这里附一张类似的流程图啦:

Spring AOP原理-代理对象的底层执行逻辑

3. Aspect中的四种通知在源码中的实现

最后,咱对 AspectJ 中提到的四种声明式的通知,它的底层实现有一个简单的了解,前面咱看过环绕通知了,所以这个咱就不列出来了。

3.1 @Before

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
	private MethodBeforeAdvice advice;

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
		return mi.proceed();
	}
}

先执行前置通知,再执行目标方法。

3.2 @After

public class AspectJAfterAdvice extends AbstractAspectJAdvice
		implements MethodInterceptor, AfterAdvice, Serializable {

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		try {
			return mi.proceed();
		}
		finally {
			invokeAdviceMethod(getJoinPointMatch(), null, null);
		}
	}
}

执行目标方法后,在 finally 中执行后置方法(由此也说明了它的通知时机更靠后)。

3.3 @AfterReturning

public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {
	private final AfterReturningAdvice advice;

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		Object retVal = mi.proceed();
		this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
		return retVal;
	}
}

返回值后置处理中不设置 try-catch 块,说明不出现任何异常时才会触发该后置通知。

3.4 @AfterThrowing

public class AspectJAfterThrowingAdvice extends AbstractAspectJAdvice
		implements MethodInterceptor, AfterAdvice, Serializable {

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		try {
			return mi.proceed();
		}
		catch (Throwable ex) {
			if (shouldInvokeOnThrowing(ex)) {
				invokeAdviceMethod(getJoinPointMatch(), null, ex);
			}
			throw ex;
		}
	}
}

出现异常时,进入该后置通知,因为设置了 try-catch ,所以这里 catch 中根据是否标注了异常通知,进行相应的后置处理。

代理对象已经创建好了,接下来就到了正常的业务代码执行了。经过 AOP 的增强后,获取到目标对象的代理对象执行方法时,就会先执行 AOP 增强中的增强器逻辑。下面咱继续以 com.linkedbear.spring.aop.b_aspectj.AnnotationAspectJApplication 中的代码来测试,执行 financeService.addMoney 方法和 orderService.getOrderById 方法的底层逻辑。

1. FinanceService#addMoney

将断点打在 addMoney 方法的调用上,Debug 进入时,会发现它先来到了 CglibAopProxy 的内部类 DynamicAdvisedInterceptor 中:(下面的源码有点长,小册把不太重要的注释都删掉,只留下重要的几个环节,小伙伴们注意留意)

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 {
        // 如果有在@EnableAspectJAutoProxy注解上配置exposeProxy属性为true,
        // 则会把当前代理对象放入AOP上下文中
        if (this.advised.exposeProxy) {
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }
        // 从TargetSource中取出目标对象
        target = targetSource.getTarget();
        Class<?> targetClass = (target != null ? target.getClass() : null);
        // 根据当前执行的方法,获取要执行的增强器,并以列表返回(链的思想)
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
        Object retVal;
        
        // 如果没有要执行的增强器,则直接执行目标方法
        if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            retVal = methodProxy.invoke(target, argsToUse);
        }
        else {
            // 否则,构造增强器链,执行增强器的逻辑
            retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
        }
        retVal = processReturnType(proxy, target, method, retVal);
        return retVal;
    } // finally ......
}

整个流程下来,核心步骤就两步:获取增强器链、执行增强器。同时这里也发现了之前咱讲过的一些小细节:exposeProxy 的实现、TargetSource 的使用等等。不过我们最需要关注的还是这两个核心部分,咱分别来研究。

1.1 getInterceptorsAndDynamicInterceptionAdvice

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
    MethodCacheKey cacheKey = new MethodCacheKey(method);
    List<Object> cached = this.methodCache.get(cacheKey);
    if (cached == null) {
        // 核心逻辑
        cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
                this, method, targetClass);
        this.methodCache.put(cacheKey, cached);
    }
    return cached;
}

很明显又是缓存的设计,第一次调用完成后,以后就直接从缓存中读了,不需要多次获取和解析。刨去这个不看,核心的方法还是 if 结构中的方法了,咱继续往里进。不过里面的逻辑有点长,咱拆开分段研究:

1.1.1 前置准备

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
        Advised config, Method method, @Nullable Class<?> targetClass) {
    // 增强器适配器的注册器,它会根据增强器来解析,返回拦截器数组
    AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
    Advisor[] advisors = config.getAdvisors();
    List<Object> interceptorList = new ArrayList<>(advisors.length);
    Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
    Boolean hasIntroductions = null;
    // ......

在循环处理增强器之前,这里先进行了一些基本的前置处理,这里它初始化了一个 AdvisorAdapterRegistry ,意为增强器适配器的注册器,它的主要作用是将 AspectJ 类型的增强器,转换为 MethodInterceptor ( AOP 联盟的那个 MethodInterceptor )并返回。此举的目的,会在接下来的 CglibMethodInvocation 中得以体现,咱这里先有个印象即可。

Debug 到此处,发现这里面有 3 个增强器的适配器,虽然没法 toString ,但看这个名也就知道,这大概就是 Logger 那个切面类中的那几个方法。

Spring AOP原理-代理对象的底层执行逻辑

1.1.2 匹配增强器

这部分开始循环匹配增强器了:

    // ......
    for (Advisor advisor : advisors) {
        if (advisor instanceof PointcutAdvisor) {
            // 此处拿到的就是AspectJ形式的通知方法封装
            PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
            if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                // 根据通知方法上的切入点表达式,判断是否可以匹配当前要执行的目标对象所属类
                MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                boolean match;
                // 引介匹配
                if (mm instanceof IntroductionAwareMethodMatcher) {
                    if (hasIntroductions == null) {
                        hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
                    }
                    match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
                }
                else {
                    // 方法匹配
                    match = mm.matches(method, actualClass);
                }
                // ......

这部分的匹配逻辑也不难,它会把上面取出来的增强器依次与当前正在调用的目标对象做匹配,匹配的方式与之前一样,都是借助 MethodMatcher 进行。

Debug 可以发现此处把 Logger 中声明的 5 个通知方法,以及 SpringFramework 内置的那个增强器,一起都收集到了:

Spring AOP原理-代理对象的底层执行逻辑

1.1.3 匹配后的处理

匹配到增强器之后,接下来就是决定如何封装为 MethodInterceptor 了:

                // ......
                if (match) {
                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                    // runtime的概念
                    if (mm.isRuntime()) {
                        for (MethodInterceptor interceptor : interceptors) {
                            interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                        }
                    } else {
                        interceptorList.addAll(Arrays.asList(interceptors));
                    }
                }
            }
        }
        // ......

这部分本身的添加并不难,不过这里面有一个 runtime 的概念,想必小伙伴们会比较懵,这里咱简单解释一下。

通常情况下,MethodMatcher 都是静态的匹配器,但 Spring 在此处做了一个设计,如果 MethodMatcher 被设置为动态的匹配器,则每次调用匹配方法时,可以提前拿到方法调用的参数值列表。说起来有点难理解,咱先看两个方法的签名:

boolean matches(Method method, Class<?> targetClass);

boolean matches(Method method, Class<?> targetClass, Object... args);

小册这样解释一下,你们都就立马明白了:静态匹配器只会做匹配,而动态的匹配器可以提前拿到方法调用的参数值列表(注意是参数值)。

1.1.4 其他增强器的处理

        // ......
        else if (advisor instanceof IntroductionAdvisor) {
            IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
            if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
                Interceptor[] interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        }
        else {
            Interceptor[] interceptors = registry.getInterceptors(advisor);
            interceptorList.addAll(Arrays.asList(interceptors));
        }
    }

    return interceptorList;
}

在最下面,就是引介增强器,以及其它类型的增强器的处理了,这里咱一般都碰不到,AspectJ 风格的声明都是走上面的 PointcutAdvisor 判断逻辑,所以咱这里就不细展开了。

经过这个方法的处理之后,当前目标对象要执行的方法就都筛选出来了,接下来就是构建方法执行器了。

1.2 CglibMethodInvocation

下面是构造的 CglibMethodInvocation ,执行 proceed 方法了,咱先看看这个 CglibMethodInvocation 是个啥:

private static class CglibMethodInvocation extends ReflectiveMethodInvocation
public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable
public interface ProxyMethodInvocation extends MethodInvocation

得了,果然还是回到 AOP 联盟定义的那个 MethodInvocation 了,那咱就知道上面的那个适配的设计了,大家都是 MethodInvocation ,那就都好说了。

接下来,咱执行 proceed 方法,而在 CglibMethodInvocation 中,它只是单纯的调用父类的 proceed 方法:

public Object proceed() throws Throwable {
    try {
        return super.proceed();
    } // catch ......
}

那往上调用,那就来到 ReflectiveMethodInvocation 类中了。

接下来的调用过程可能会很绕,小册尝试用过程的方式记录每一步的执行动作和逻辑,方便小伙伴们体会这里面的高深设计。

1.2.0 方法概览

先大概看一下 proceed 方法的设计吧,

protected final List<?> interceptorsAndDynamicMethodMatchers;
private int currentInterceptorIndex = -1;

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) {
        // 此处是动态匹配器构造的特殊逻辑
        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 {
            return proceed();
        }
    }
    else {
        // 此处会调用增强器的逻辑
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
}

这里先解释一波动态匹配器的逻辑,看中间的 if 部分,如果 MethodMatcher 有被封装为动态匹配器,则这里会继续匹配,如果动态匹配器在匹配到方法调用的参数值列表发现匹配不上,则这个增强器不会执行。

其余的部分,就看接下来的执行逻辑咯,小伙伴们不要被小册搞晕哦。

1.2.1 执行proceed方法

public Object proceed() throws Throwable {
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return invokeJoinpoint();
    }

此时的 currentInterceptorIndex 下标值为 -1 :

Spring AOP原理-代理对象的底层执行逻辑

计算值:-1 ≠ 3 - 1,则不进入 invokeJoinpoint 方法,继续往下走。

1.2.2 下标值++

接下来,执行下面的 this.interceptorsAndDynamicMethodMatchers.get 动作,此时 this.currentInterceptorIndex 执行了一次自增操作:

    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return invokeJoinpoint();
    }

    Object interceptorOrInterceptionAdvice =
            this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {

此时 currentInterceptorIndex 值为 0 。

1.2.3 执行第一个增强器

既然获取到了增强器对应的拦截器,那就执行它:

public Object invoke(MethodInvocation mi) throws Throwable {
    MethodInvocation oldInvocation = invocation.get();
    invocation.set(mi);
    try {
        return mi.proceed();
    }
    finally {
        invocation.set(oldInvocation);
    }
}

又看到这个 invoke 方法了,咱已经挺熟悉了,下一步肯定是继续执行 proceed 方法嘛。

1.2.4 继续执行proceed方法

接下来执行 proceed 方法,会发现它又回到上面的 1.2.1 步了,只不过此时的 currentInterceptorIndex 值不再是 -1 ,而是 0 。

Spring AOP原理-代理对象的底层执行逻辑

计算值:0 ≠ 3 - 1,则不进入 invokeJoinpoint 方法,继续往下走。

1.2.5 进入AspectJAroundAdvice中

那既然计算结果不等,那就继续执行增强器逻辑嘛,由于接下来要执行的是一个环绕通知,咱来到 AspectJAroundAdvice 的 invoke 方法中:

public Object invoke(MethodInvocation mi) throws Throwable {
    if (!(mi instanceof ProxyMethodInvocation)) {
        throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
    }
    ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
    ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
    JoinPointMatch jpm = getJoinPointMatch(pmi);
    return invokeAdviceMethod(pjp, jpm, null, null);
}

前面的获取都是很基本的了,最下面的 invokeAdviceMethod 才是关键:

protected Object invokeAdviceMethod(JoinPoint jp, @Nullable JoinPointMatch jpMatch,
        @Nullable Object returnValue, @Nullable Throwable t) throws Throwable {
    return invokeAdviceMethodWithGivenArgs(argBinding(jp, jpMatch, returnValue, t));
}

protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
    Object[] actualArgs = args;
    if (this.aspectJAdviceMethod.getParameterCount() == 0) {
        actualArgs = null;
    }
    try {
        ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
        return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
    } // catch ......
}

合着折腾到最后,还是个反射执行目标对象的方法。。。

1.2.6 进入到Logger中

因为是环绕通知嘛,那就理所应当的进入到 Logger 中了:

@Around("execution(public * com.linkedbear.spring.aop.b_aspectj.service.FinanceService.addMoney(..))")
public Object aroundPrint(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("Logger aroundPrint before run ......");
    try {
        Object retVal = joinPoint.proceed();
        System.out.println("Logger aroundPrint afterReturning run ......");
        return retVal;
    } // catch finally ......
}

执行了前置通知打印后,接下来的 joinPoint.proceed 方法的执行,想必不用小册解释,小伙伴们也能想得到了吧。

1.2.7 继续执行proceed方法

想是想到了,但这个中间还有个小插曲。。。proceed 方法的执行,肯定是走的 ProceedingJoinPoint 的 proceed 方法呀,不是上面 ReflectiveMethodInvocation 的:

public Object proceed() throws Throwable {
    return this.methodInvocation.invocableClone().proceed();
}

哎,这里的 proceed 方法,才是上面咱执行那些 proceed 方法,此时 currentInterceptorIndex 的值为 1 :

Spring AOP原理-代理对象的底层执行逻辑

然后,又是同样的获取、自增、执行。。。

1.2.8 进入MethodBeforeAdviceInterceptor中

第三个通知方法的执行,是那个前置通知,它会来到 MethodBeforeAdviceInterceptor 中:

public Object invoke(MethodInvocation mi) throws Throwable {
    this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
    return mi.proceed();
}

可以发现还蛮简单的,它就是把前置通知的方法执行一下,然后继续执行 MethodInvocation 的 proceed 方法了。

1.2.9 执行目标对象方法

接下来,又回到 proceed 方法,此时 currentInterceptorIndex 的值为 2 :

计算得 2 = 3 - 1 ,终于相等了,那就可以执行目标方法了。

1.2.10 流程小结

好了,经过这个流程之后,咱终于走完这个全程,由此我们可以得出算法逻辑:

利用一个全局索引值,决定每次执行的拦截器,当所有拦截器都执行完时,索引值刚好等于 size() - 1,此时就可以执行真正的目标方法了 。

最后用一张图来更好地理解这段逻辑:

Spring AOP原理-代理对象的底层执行逻辑

2. OrderService#getOrderById

咱继续研究 jdk 动态代理的执行。将断点打在 getOrderById 方法的调用上,Debug 进入时它肯定就不跟上面的 Cglib 动态代理一样了,它进入的是 JdkDynamicAopProxy 中。不过由于这里面的 invoke 方法实在是有点长,小册在这里只截取关键部分:

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

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

    try {
        // equals方法不代理
        if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
            // The target does not implement the equals(Object) method itself.
            return equals(args[0]);
        }
        // hashCode方法不代理
        else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
            // The target does not implement the hashCode() method itself.
            return hashCode();
        }
        // 方法来自于DecoratingProxy接口的,也不代理
        else if (method.getDeclaringClass() == DecoratingProxy.class) {
            // There is only getDecoratedClass() declared -> dispatch to proxy config.
            return AopProxyUtils.ultimateTargetClass(this.advised);
        }
        // 目标对象本身就是实现了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) {
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }

        target = targetSource.getTarget();
        Class<?> targetClass = (target != null ? target.getClass() : null);

        // 根据当前执行的方法,获取要执行的增强器,并以列表返回(链的思想)
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
        if (chain.isEmpty()) {
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
        }
        else {
            MethodInvocation invocation =
                    new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
            // 构造增强器链,执行增强器的逻辑
            retVal = invocation.proceed();
        }
        // 返回值的处理 ......
        return retVal;
    } // finally ......
}

先看下面的部分,是不是跟上面 CglibAopProxy 完全一致?所以 这两者其实在底层实现中都是一样的,包括这里它创建的直接就是 ReflectiveMethodInvocation ,与上面咱看到的那个家伙是同一个。

所以这个逻辑也是一模一样的吧,具体流程这个就留给小伙伴当课后作业了,小册只在这里附一张类似的流程图啦:

Spring AOP原理-代理对象的底层执行逻辑

3. Aspect中的四种通知在源码中的实现

最后,咱对 AspectJ 中提到的四种声明式的通知,它的底层实现有一个简单的了解,前面咱看过环绕通知了,所以这个咱就不列出来了。

3.1 @Before

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
	private MethodBeforeAdvice advice;

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
		return mi.proceed();
	}
}

先执行前置通知,再执行目标方法。

3.2 @After

public class AspectJAfterAdvice extends AbstractAspectJAdvice
		implements MethodInterceptor, AfterAdvice, Serializable {

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		try {
			return mi.proceed();
		}
		finally {
			invokeAdviceMethod(getJoinPointMatch(), null, null);
		}
	}
}

执行目标方法后,在 finally 中执行后置方法(由此也说明了它的通知时机更靠后)。

3.3 @AfterReturning

public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {
	private final AfterReturningAdvice advice;

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		Object retVal = mi.proceed();
		this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
		return retVal;
	}
}

返回值后置处理中不设置 try-catch 块,说明不出现任何异常时才会触发该后置通知。

3.4 @AfterThrowing

public class AspectJAfterThrowingAdvice extends AbstractAspectJAdvice
		implements MethodInterceptor, AfterAdvice, Serializable {

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		try {
			return mi.proceed();
		}
		catch (Throwable ex) {
			if (shouldInvokeOnThrowing(ex)) {
				invokeAdviceMethod(getJoinPointMatch(), null, ex);
			}
			throw ex;
		}
	}
}

出现异常时,进入该后置通知,因为设置了 try-catch ,所以这里 catch 中根据是否标注了异常通知,进行相应的后置处理。

代理对象已经创建好了,接下来就到了正常的业务代码执行了。经过 AOP 的增强后,获取到目标对象的代理对象执行方法时,就会先执行 AOP 增强中的增强器逻辑。下面咱继续以 com.linkedbear.spring.aop.b_aspectj.AnnotationAspectJApplication 中的代码来测试,执行 financeService.addMoney 方法和 orderService.getOrderById 方法的底层逻辑。

1. FinanceService#addMoney

将断点打在 addMoney 方法的调用上,Debug 进入时,会发现它先来到了 CglibAopProxy 的内部类 DynamicAdvisedInterceptor 中:(下面的源码有点长,小册把不太重要的注释都删掉,只留下重要的几个环节,小伙伴们注意留意)

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 {
        // 如果有在@EnableAspectJAutoProxy注解上配置exposeProxy属性为true,
        // 则会把当前代理对象放入AOP上下文中
        if (this.advised.exposeProxy) {
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }
        // 从TargetSource中取出目标对象
        target = targetSource.getTarget();
        Class<?> targetClass = (target != null ? target.getClass() : null);
        // 根据当前执行的方法,获取要执行的增强器,并以列表返回(链的思想)
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
        Object retVal;
        
        // 如果没有要执行的增强器,则直接执行目标方法
        if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            retVal = methodProxy.invoke(target, argsToUse);
        }
        else {
            // 否则,构造增强器链,执行增强器的逻辑
            retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
        }
        retVal = processReturnType(proxy, target, method, retVal);
        return retVal;
    } // finally ......
}

整个流程下来,核心步骤就两步:获取增强器链、执行增强器。同时这里也发现了之前咱讲过的一些小细节:exposeProxy 的实现、TargetSource 的使用等等。不过我们最需要关注的还是这两个核心部分,咱分别来研究。

1.1 getInterceptorsAndDynamicInterceptionAdvice

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
    MethodCacheKey cacheKey = new MethodCacheKey(method);
    List<Object> cached = this.methodCache.get(cacheKey);
    if (cached == null) {
        // 核心逻辑
        cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
                this, method, targetClass);
        this.methodCache.put(cacheKey, cached);
    }
    return cached;
}

很明显又是缓存的设计,第一次调用完成后,以后就直接从缓存中读了,不需要多次获取和解析。刨去这个不看,核心的方法还是 if 结构中的方法了,咱继续往里进。不过里面的逻辑有点长,咱拆开分段研究:

1.1.1 前置准备

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
        Advised config, Method method, @Nullable Class<?> targetClass) {
    // 增强器适配器的注册器,它会根据增强器来解析,返回拦截器数组
    AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
    Advisor[] advisors = config.getAdvisors();
    List<Object> interceptorList = new ArrayList<>(advisors.length);
    Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
    Boolean hasIntroductions = null;
    // ......

在循环处理增强器之前,这里先进行了一些基本的前置处理,这里它初始化了一个 AdvisorAdapterRegistry ,意为增强器适配器的注册器,它的主要作用是将 AspectJ 类型的增强器,转换为 MethodInterceptor ( AOP 联盟的那个 MethodInterceptor )并返回。此举的目的,会在接下来的 CglibMethodInvocation 中得以体现,咱这里先有个印象即可。

Debug 到此处,发现这里面有 3 个增强器的适配器,虽然没法 toString ,但看这个名也就知道,这大概就是 Logger 那个切面类中的那几个方法。

Spring AOP原理-代理对象的底层执行逻辑

1.1.2 匹配增强器

这部分开始循环匹配增强器了:

    // ......
    for (Advisor advisor : advisors) {
        if (advisor instanceof PointcutAdvisor) {
            // 此处拿到的就是AspectJ形式的通知方法封装
            PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
            if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                // 根据通知方法上的切入点表达式,判断是否可以匹配当前要执行的目标对象所属类
                MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                boolean match;
                // 引介匹配
                if (mm instanceof IntroductionAwareMethodMatcher) {
                    if (hasIntroductions == null) {
                        hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
                    }
                    match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
                }
                else {
                    // 方法匹配
                    match = mm.matches(method, actualClass);
                }
                // ......

这部分的匹配逻辑也不难,它会把上面取出来的增强器依次与当前正在调用的目标对象做匹配,匹配的方式与之前一样,都是借助 MethodMatcher 进行。

Debug 可以发现此处把 Logger 中声明的 5 个通知方法,以及 SpringFramework 内置的那个增强器,一起都收集到了:

Spring AOP原理-代理对象的底层执行逻辑

1.1.3 匹配后的处理

匹配到增强器之后,接下来就是决定如何封装为 MethodInterceptor 了:

                // ......
                if (match) {
                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                    // runtime的概念
                    if (mm.isRuntime()) {
                        for (MethodInterceptor interceptor : interceptors) {
                            interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                        }
                    } else {
                        interceptorList.addAll(Arrays.asList(interceptors));
                    }
                }
            }
        }
        // ......

这部分本身的添加并不难,不过这里面有一个 runtime 的概念,想必小伙伴们会比较懵,这里咱简单解释一下。

通常情况下,MethodMatcher 都是静态的匹配器,但 Spring 在此处做了一个设计,如果 MethodMatcher 被设置为动态的匹配器,则每次调用匹配方法时,可以提前拿到方法调用的参数值列表。说起来有点难理解,咱先看两个方法的签名:

boolean matches(Method method, Class<?> targetClass);

boolean matches(Method method, Class<?> targetClass, Object... args);

小册这样解释一下,你们都就立马明白了:静态匹配器只会做匹配,而动态的匹配器可以提前拿到方法调用的参数值列表(注意是参数值)。

1.1.4 其他增强器的处理

        // ......
        else if (advisor instanceof IntroductionAdvisor) {
            IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
            if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
                Interceptor[] interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        }
        else {
            Interceptor[] interceptors = registry.getInterceptors(advisor);
            interceptorList.addAll(Arrays.asList(interceptors));
        }
    }

    return interceptorList;
}

在最下面,就是引介增强器,以及其它类型的增强器的处理了,这里咱一般都碰不到,AspectJ 风格的声明都是走上面的 PointcutAdvisor 判断逻辑,所以咱这里就不细展开了。

经过这个方法的处理之后,当前目标对象要执行的方法就都筛选出来了,接下来就是构建方法执行器了。

1.2 CglibMethodInvocation

下面是构造的 CglibMethodInvocation ,执行 proceed 方法了,咱先看看这个 CglibMethodInvocation 是个啥:

private static class CglibMethodInvocation extends ReflectiveMethodInvocation
public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable
public interface ProxyMethodInvocation extends MethodInvocation

得了,果然还是回到 AOP 联盟定义的那个 MethodInvocation 了,那咱就知道上面的那个适配的设计了,大家都是 MethodInvocation ,那就都好说了。

接下来,咱执行 proceed 方法,而在 CglibMethodInvocation 中,它只是单纯的调用父类的 proceed 方法:

public Object proceed() throws Throwable {
    try {
        return super.proceed();
    } // catch ......
}

那往上调用,那就来到 ReflectiveMethodInvocation 类中了。

接下来的调用过程可能会很绕,小册尝试用过程的方式记录每一步的执行动作和逻辑,方便小伙伴们体会这里面的高深设计。

1.2.0 方法概览

先大概看一下 proceed 方法的设计吧,

protected final List<?> interceptorsAndDynamicMethodMatchers;
private int currentInterceptorIndex = -1;

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) {
        // 此处是动态匹配器构造的特殊逻辑
        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 {
            return proceed();
        }
    }
    else {
        // 此处会调用增强器的逻辑
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
}

这里先解释一波动态匹配器的逻辑,看中间的 if 部分,如果 MethodMatcher 有被封装为动态匹配器,则这里会继续匹配,如果动态匹配器在匹配到方法调用的参数值列表发现匹配不上,则这个增强器不会执行。

其余的部分,就看接下来的执行逻辑咯,小伙伴们不要被小册搞晕哦。

1.2.1 执行proceed方法

public Object proceed() throws Throwable {
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return invokeJoinpoint();
    }

此时的 currentInterceptorIndex 下标值为 -1 :

Spring AOP原理-代理对象的底层执行逻辑

计算值:-1 ≠ 3 - 1,则不进入 invokeJoinpoint 方法,继续往下走。

1.2.2 下标值++

接下来,执行下面的 this.interceptorsAndDynamicMethodMatchers.get 动作,此时 this.currentInterceptorIndex 执行了一次自增操作:

    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return invokeJoinpoint();
    }

    Object interceptorOrInterceptionAdvice =
            this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {

此时 currentInterceptorIndex 值为 0 。

1.2.3 执行第一个增强器

既然获取到了增强器对应的拦截器,那就执行它:

public Object invoke(MethodInvocation mi) throws Throwable {
    MethodInvocation oldInvocation = invocation.get();
    invocation.set(mi);
    try {
        return mi.proceed();
    }
    finally {
        invocation.set(oldInvocation);
    }
}

又看到这个 invoke 方法了,咱已经挺熟悉了,下一步肯定是继续执行 proceed 方法嘛。

1.2.4 继续执行proceed方法

接下来执行 proceed 方法,会发现它又回到上面的 1.2.1 步了,只不过此时的 currentInterceptorIndex 值不再是 -1 ,而是 0 。

Spring AOP原理-代理对象的底层执行逻辑

计算值:0 ≠ 3 - 1,则不进入 invokeJoinpoint 方法,继续往下走。

1.2.5 进入AspectJAroundAdvice中

那既然计算结果不等,那就继续执行增强器逻辑嘛,由于接下来要执行的是一个环绕通知,咱来到 AspectJAroundAdvice 的 invoke 方法中:

public Object invoke(MethodInvocation mi) throws Throwable {
    if (!(mi instanceof ProxyMethodInvocation)) {
        throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
    }
    ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
    ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
    JoinPointMatch jpm = getJoinPointMatch(pmi);
    return invokeAdviceMethod(pjp, jpm, null, null);
}

前面的获取都是很基本的了,最下面的 invokeAdviceMethod 才是关键:

protected Object invokeAdviceMethod(JoinPoint jp, @Nullable JoinPointMatch jpMatch,
        @Nullable Object returnValue, @Nullable Throwable t) throws Throwable {
    return invokeAdviceMethodWithGivenArgs(argBinding(jp, jpMatch, returnValue, t));
}

protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
    Object[] actualArgs = args;
    if (this.aspectJAdviceMethod.getParameterCount() == 0) {
        actualArgs = null;
    }
    try {
        ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
        return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
    } // catch ......
}

合着折腾到最后,还是个反射执行目标对象的方法。。。

1.2.6 进入到Logger中

因为是环绕通知嘛,那就理所应当的进入到 Logger 中了:

@Around("execution(public * com.linkedbear.spring.aop.b_aspectj.service.FinanceService.addMoney(..))")
public Object aroundPrint(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("Logger aroundPrint before run ......");
    try {
        Object retVal = joinPoint.proceed();
        System.out.println("Logger aroundPrint afterReturning run ......");
        return retVal;
    } // catch finally ......
}

执行了前置通知打印后,接下来的 joinPoint.proceed 方法的执行,想必不用小册解释,小伙伴们也能想得到了吧。

1.2.7 继续执行proceed方法

想是想到了,但这个中间还有个小插曲。。。proceed 方法的执行,肯定是走的 ProceedingJoinPoint 的 proceed 方法呀,不是上面 ReflectiveMethodInvocation 的:

public Object proceed() throws Throwable {
    return this.methodInvocation.invocableClone().proceed();
}

哎,这里的 proceed 方法,才是上面咱执行那些 proceed 方法,此时 currentInterceptorIndex 的值为 1 :

Spring AOP原理-代理对象的底层执行逻辑

然后,又是同样的获取、自增、执行。。。

1.2.8 进入MethodBeforeAdviceInterceptor中

第三个通知方法的执行,是那个前置通知,它会来到 MethodBeforeAdviceInterceptor 中:

public Object invoke(MethodInvocation mi) throws Throwable {
    this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
    return mi.proceed();
}

可以发现还蛮简单的,它就是把前置通知的方法执行一下,然后继续执行 MethodInvocation 的 proceed 方法了。

1.2.9 执行目标对象方法

接下来,又回到 proceed 方法,此时 currentInterceptorIndex 的值为 2 :

计算得 2 = 3 - 1 ,终于相等了,那就可以执行目标方法了。

1.2.10 流程小结

好了,经过这个流程之后,咱终于走完这个全程,由此我们可以得出算法逻辑:

利用一个全局索引值,决定每次执行的拦截器,当所有拦截器都执行完时,索引值刚好等于 size() - 1,此时就可以执行真正的目标方法了 。

最后用一张图来更好地理解这段逻辑:

Spring AOP原理-代理对象的底层执行逻辑

2. OrderService#getOrderById

咱继续研究 jdk 动态代理的执行。将断点打在 getOrderById 方法的调用上,Debug 进入时它肯定就不跟上面的 Cglib 动态代理一样了,它进入的是 JdkDynamicAopProxy 中。不过由于这里面的 invoke 方法实在是有点长,小册在这里只截取关键部分:

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

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

    try {
        // equals方法不代理
        if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
            // The target does not implement the equals(Object) method itself.
            return equals(args[0]);
        }
        // hashCode方法不代理
        else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
            // The target does not implement the hashCode() method itself.
            return hashCode();
        }
        // 方法来自于DecoratingProxy接口的,也不代理
        else if (method.getDeclaringClass() == DecoratingProxy.class) {
            // There is only getDecoratedClass() declared -> dispatch to proxy config.
            return AopProxyUtils.ultimateTargetClass(this.advised);
        }
        // 目标对象本身就是实现了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) {
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }

        target = targetSource.getTarget();
        Class<?> targetClass = (target != null ? target.getClass() : null);

        // 根据当前执行的方法,获取要执行的增强器,并以列表返回(链的思想)
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
        if (chain.isEmpty()) {
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
        }
        else {
            MethodInvocation invocation =
                    new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
            // 构造增强器链,执行增强器的逻辑
            retVal = invocation.proceed();
        }
        // 返回值的处理 ......
        return retVal;
    } // finally ......
}

先看下面的部分,是不是跟上面 CglibAopProxy 完全一致?所以 这两者其实在底层实现中都是一样的,包括这里它创建的直接就是 ReflectiveMethodInvocation ,与上面咱看到的那个家伙是同一个。

所以这个逻辑也是一模一样的吧,具体流程这个就留给小伙伴当课后作业了,小册只在这里附一张类似的流程图啦:

Spring AOP原理-代理对象的底层执行逻辑

3. Aspect中的四种通知在源码中的实现

最后,咱对 AspectJ 中提到的四种声明式的通知,它的底层实现有一个简单的了解,前面咱看过环绕通知了,所以这个咱就不列出来了。

3.1 @Before

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
	private MethodBeforeAdvice advice;

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
		return mi.proceed();
	}
}

先执行前置通知,再执行目标方法。

3.2 @After

public class AspectJAfterAdvice extends AbstractAspectJAdvice
		implements MethodInterceptor, AfterAdvice, Serializable {

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		try {
			return mi.proceed();
		}
		finally {
			invokeAdviceMethod(getJoinPointMatch(), null, null);
		}
	}
}

执行目标方法后,在 finally 中执行后置方法(由此也说明了它的通知时机更靠后)。

3.3 @AfterReturning

public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {
	private final AfterReturningAdvice advice;

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		Object retVal = mi.proceed();
		this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
		return retVal;
	}
}

返回值后置处理中不设置 try-catch 块,说明不出现任何异常时才会触发该后置通知。

3.4 @AfterThrowing

public class AspectJAfterThrowingAdvice extends AbstractAspectJAdvice
		implements MethodInterceptor, AfterAdvice, Serializable {

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		try {
			return mi.proceed();
		}
		catch (Throwable ex) {
			if (shouldInvokeOnThrowing(ex)) {
				invokeAdviceMethod(getJoinPointMatch(), null, ex);
			}
			throw ex;
		}
	}
}

出现异常时,进入该后置通知,因为设置了 try-catch ,所以这里 catch 中根据是否标注了异常通知,进行相应的后置处理。

代理对象已经创建好了,接下来就到了正常的业务代码执行了。经过 AOP 的增强后,获取到目标对象的代理对象执行方法时,就会先执行 AOP 增强中的增强器逻辑。下面咱继续以 com.linkedbear.spring.aop.b_aspectj.AnnotationAspectJApplication 中的代码来测试,执行 financeService.addMoney 方法和 orderService.getOrderById 方法的底层逻辑。

1. FinanceService#addMoney

将断点打在 addMoney 方法的调用上,Debug 进入时,会发现它先来到了 CglibAopProxy 的内部类 DynamicAdvisedInterceptor 中:(下面的源码有点长,小册把不太重要的注释都删掉,只留下重要的几个环节,小伙伴们注意留意)

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 {
        // 如果有在@EnableAspectJAutoProxy注解上配置exposeProxy属性为true,
        // 则会把当前代理对象放入AOP上下文中
        if (this.advised.exposeProxy) {
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }
        // 从TargetSource中取出目标对象
        target = targetSource.getTarget();
        Class<?> targetClass = (target != null ? target.getClass() : null);
        // 根据当前执行的方法,获取要执行的增强器,并以列表返回(链的思想)
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
        Object retVal;
        
        // 如果没有要执行的增强器,则直接执行目标方法
        if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            retVal = methodProxy.invoke(target, argsToUse);
        }
        else {
            // 否则,构造增强器链,执行增强器的逻辑
            retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
        }
        retVal = processReturnType(proxy, target, method, retVal);
        return retVal;
    } // finally ......
}

整个流程下来,核心步骤就两步:获取增强器链、执行增强器。同时这里也发现了之前咱讲过的一些小细节:exposeProxy 的实现、TargetSource 的使用等等。不过我们最需要关注的还是这两个核心部分,咱分别来研究。

1.1 getInterceptorsAndDynamicInterceptionAdvice

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
    MethodCacheKey cacheKey = new MethodCacheKey(method);
    List<Object> cached = this.methodCache.get(cacheKey);
    if (cached == null) {
        // 核心逻辑
        cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
                this, method, targetClass);
        this.methodCache.put(cacheKey, cached);
    }
    return cached;
}

很明显又是缓存的设计,第一次调用完成后,以后就直接从缓存中读了,不需要多次获取和解析。刨去这个不看,核心的方法还是 if 结构中的方法了,咱继续往里进。不过里面的逻辑有点长,咱拆开分段研究:

1.1.1 前置准备

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
        Advised config, Method method, @Nullable Class<?> targetClass) {
    // 增强器适配器的注册器,它会根据增强器来解析,返回拦截器数组
    AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
    Advisor[] advisors = config.getAdvisors();
    List<Object> interceptorList = new ArrayList<>(advisors.length);
    Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
    Boolean hasIntroductions = null;
    // ......

在循环处理增强器之前,这里先进行了一些基本的前置处理,这里它初始化了一个 AdvisorAdapterRegistry ,意为增强器适配器的注册器,它的主要作用是将 AspectJ 类型的增强器,转换为 MethodInterceptor ( AOP 联盟的那个 MethodInterceptor )并返回。此举的目的,会在接下来的 CglibMethodInvocation 中得以体现,咱这里先有个印象即可。

Debug 到此处,发现这里面有 3 个增强器的适配器,虽然没法 toString ,但看这个名也就知道,这大概就是 Logger 那个切面类中的那几个方法。

Spring AOP原理-代理对象的底层执行逻辑

1.1.2 匹配增强器

这部分开始循环匹配增强器了:

    // ......
    for (Advisor advisor : advisors) {
        if (advisor instanceof PointcutAdvisor) {
            // 此处拿到的就是AspectJ形式的通知方法封装
            PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
            if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                // 根据通知方法上的切入点表达式,判断是否可以匹配当前要执行的目标对象所属类
                MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                boolean match;
                // 引介匹配
                if (mm instanceof IntroductionAwareMethodMatcher) {
                    if (hasIntroductions == null) {
                        hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
                    }
                    match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
                }
                else {
                    // 方法匹配
                    match = mm.matches(method, actualClass);
                }
                // ......

这部分的匹配逻辑也不难,它会把上面取出来的增强器依次与当前正在调用的目标对象做匹配,匹配的方式与之前一样,都是借助 MethodMatcher 进行。

Debug 可以发现此处把 Logger 中声明的 5 个通知方法,以及 SpringFramework 内置的那个增强器,一起都收集到了:

Spring AOP原理-代理对象的底层执行逻辑

1.1.3 匹配后的处理

匹配到增强器之后,接下来就是决定如何封装为 MethodInterceptor 了:

                // ......
                if (match) {
                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                    // runtime的概念
                    if (mm.isRuntime()) {
                        for (MethodInterceptor interceptor : interceptors) {
                            interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                        }
                    } else {
                        interceptorList.addAll(Arrays.asList(interceptors));
                    }
                }
            }
        }
        // ......

这部分本身的添加并不难,不过这里面有一个 runtime 的概念,想必小伙伴们会比较懵,这里咱简单解释一下。

通常情况下,MethodMatcher 都是静态的匹配器,但 Spring 在此处做了一个设计,如果 MethodMatcher 被设置为动态的匹配器,则每次调用匹配方法时,可以提前拿到方法调用的参数值列表。说起来有点难理解,咱先看两个方法的签名:

boolean matches(Method method, Class<?> targetClass);

boolean matches(Method method, Class<?> targetClass, Object... args);

小册这样解释一下,你们都就立马明白了:静态匹配器只会做匹配,而动态的匹配器可以提前拿到方法调用的参数值列表(注意是参数值)。

1.1.4 其他增强器的处理

        // ......
        else if (advisor instanceof IntroductionAdvisor) {
            IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
            if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
                Interceptor[] interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        }
        else {
            Interceptor[] interceptors = registry.getInterceptors(advisor);
            interceptorList.addAll(Arrays.asList(interceptors));
        }
    }

    return interceptorList;
}

在最下面,就是引介增强器,以及其它类型的增强器的处理了,这里咱一般都碰不到,AspectJ 风格的声明都是走上面的 PointcutAdvisor 判断逻辑,所以咱这里就不细展开了。

经过这个方法的处理之后,当前目标对象要执行的方法就都筛选出来了,接下来就是构建方法执行器了。

1.2 CglibMethodInvocation

下面是构造的 CglibMethodInvocation ,执行 proceed 方法了,咱先看看这个 CglibMethodInvocation 是个啥:

private static class CglibMethodInvocation extends ReflectiveMethodInvocation
public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable
public interface ProxyMethodInvocation extends MethodInvocation

得了,果然还是回到 AOP 联盟定义的那个 MethodInvocation 了,那咱就知道上面的那个适配的设计了,大家都是 MethodInvocation ,那就都好说了。

接下来,咱执行 proceed 方法,而在 CglibMethodInvocation 中,它只是单纯的调用父类的 proceed 方法:

public Object proceed() throws Throwable {
    try {
        return super.proceed();
    } // catch ......
}

那往上调用,那就来到 ReflectiveMethodInvocation 类中了。

接下来的调用过程可能会很绕,小册尝试用过程的方式记录每一步的执行动作和逻辑,方便小伙伴们体会这里面的高深设计。

1.2.0 方法概览

先大概看一下 proceed 方法的设计吧,

protected final List<?> interceptorsAndDynamicMethodMatchers;
private int currentInterceptorIndex = -1;

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) {
        // 此处是动态匹配器构造的特殊逻辑
        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 {
            return proceed();
        }
    }
    else {
        // 此处会调用增强器的逻辑
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
}

这里先解释一波动态匹配器的逻辑,看中间的 if 部分,如果 MethodMatcher 有被封装为动态匹配器,则这里会继续匹配,如果动态匹配器在匹配到方法调用的参数值列表发现匹配不上,则这个增强器不会执行。

其余的部分,就看接下来的执行逻辑咯,小伙伴们不要被小册搞晕哦。

1.2.1 执行proceed方法

public Object proceed() throws Throwable {
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return invokeJoinpoint();
    }

此时的 currentInterceptorIndex 下标值为 -1 :

Spring AOP原理-代理对象的底层执行逻辑

计算值:-1 ≠ 3 - 1,则不进入 invokeJoinpoint 方法,继续往下走。

1.2.2 下标值++

接下来,执行下面的 this.interceptorsAndDynamicMethodMatchers.get 动作,此时 this.currentInterceptorIndex 执行了一次自增操作:

    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return invokeJoinpoint();
    }

    Object interceptorOrInterceptionAdvice =
            this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {

此时 currentInterceptorIndex 值为 0 。

1.2.3 执行第一个增强器

既然获取到了增强器对应的拦截器,那就执行它:

public Object invoke(MethodInvocation mi) throws Throwable {
    MethodInvocation oldInvocation = invocation.get();
    invocation.set(mi);
    try {
        return mi.proceed();
    }
    finally {
        invocation.set(oldInvocation);
    }
}

又看到这个 invoke 方法了,咱已经挺熟悉了,下一步肯定是继续执行 proceed 方法嘛。

1.2.4 继续执行proceed方法

接下来执行 proceed 方法,会发现它又回到上面的 1.2.1 步了,只不过此时的 currentInterceptorIndex 值不再是 -1 ,而是 0 。

Spring AOP原理-代理对象的底层执行逻辑

计算值:0 ≠ 3 - 1,则不进入 invokeJoinpoint 方法,继续往下走。

1.2.5 进入AspectJAroundAdvice中

那既然计算结果不等,那就继续执行增强器逻辑嘛,由于接下来要执行的是一个环绕通知,咱来到 AspectJAroundAdvice 的 invoke 方法中:

public Object invoke(MethodInvocation mi) throws Throwable {
    if (!(mi instanceof ProxyMethodInvocation)) {
        throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
    }
    ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
    ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
    JoinPointMatch jpm = getJoinPointMatch(pmi);
    return invokeAdviceMethod(pjp, jpm, null, null);
}

前面的获取都是很基本的了,最下面的 invokeAdviceMethod 才是关键:

protected Object invokeAdviceMethod(JoinPoint jp, @Nullable JoinPointMatch jpMatch,
        @Nullable Object returnValue, @Nullable Throwable t) throws Throwable {
    return invokeAdviceMethodWithGivenArgs(argBinding(jp, jpMatch, returnValue, t));
}

protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
    Object[] actualArgs = args;
    if (this.aspectJAdviceMethod.getParameterCount() == 0) {
        actualArgs = null;
    }
    try {
        ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
        return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
    } // catch ......
}

合着折腾到最后,还是个反射执行目标对象的方法。。。

1.2.6 进入到Logger中

因为是环绕通知嘛,那就理所应当的进入到 Logger 中了:

@Around("execution(public * com.linkedbear.spring.aop.b_aspectj.service.FinanceService.addMoney(..))")
public Object aroundPrint(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("Logger aroundPrint before run ......");
    try {
        Object retVal = joinPoint.proceed();
        System.out.println("Logger aroundPrint afterReturning run ......");
        return retVal;
    } // catch finally ......
}

执行了前置通知打印后,接下来的 joinPoint.proceed 方法的执行,想必不用小册解释,小伙伴们也能想得到了吧。

1.2.7 继续执行proceed方法

想是想到了,但这个中间还有个小插曲。。。proceed 方法的执行,肯定是走的 ProceedingJoinPoint 的 proceed 方法呀,不是上面 ReflectiveMethodInvocation 的:

public Object proceed() throws Throwable {
    return this.methodInvocation.invocableClone().proceed();
}

哎,这里的 proceed 方法,才是上面咱执行那些 proceed 方法,此时 currentInterceptorIndex 的值为 1 :

Spring AOP原理-代理对象的底层执行逻辑

然后,又是同样的获取、自增、执行。。。

1.2.8 进入MethodBeforeAdviceInterceptor中

第三个通知方法的执行,是那个前置通知,它会来到 MethodBeforeAdviceInterceptor 中:

public Object invoke(MethodInvocation mi) throws Throwable {
    this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
    return mi.proceed();
}

可以发现还蛮简单的,它就是把前置通知的方法执行一下,然后继续执行 MethodInvocation 的 proceed 方法了。

1.2.9 执行目标对象方法

接下来,又回到 proceed 方法,此时 currentInterceptorIndex 的值为 2 :

计算得 2 = 3 - 1 ,终于相等了,那就可以执行目标方法了。

1.2.10 流程小结

好了,经过这个流程之后,咱终于走完这个全程,由此我们可以得出算法逻辑:

利用一个全局索引值,决定每次执行的拦截器,当所有拦截器都执行完时,索引值刚好等于 size() - 1,此时就可以执行真正的目标方法了 。

最后用一张图来更好地理解这段逻辑:

Spring AOP原理-代理对象的底层执行逻辑

2. OrderService#getOrderById

咱继续研究 jdk 动态代理的执行。将断点打在 getOrderById 方法的调用上,Debug 进入时它肯定就不跟上面的 Cglib 动态代理一样了,它进入的是 JdkDynamicAopProxy 中。不过由于这里面的 invoke 方法实在是有点长,小册在这里只截取关键部分:

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

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

    try {
        // equals方法不代理
        if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
            // The target does not implement the equals(Object) method itself.
            return equals(args[0]);
        }
        // hashCode方法不代理
        else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
            // The target does not implement the hashCode() method itself.
            return hashCode();
        }
        // 方法来自于DecoratingProxy接口的,也不代理
        else if (method.getDeclaringClass() == DecoratingProxy.class) {
            // There is only getDecoratedClass() declared -> dispatch to proxy config.
            return AopProxyUtils.ultimateTargetClass(this.advised);
        }
        // 目标对象本身就是实现了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) {
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }

        target = targetSource.getTarget();
        Class<?> targetClass = (target != null ? target.getClass() : null);

        // 根据当前执行的方法,获取要执行的增强器,并以列表返回(链的思想)
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
        if (chain.isEmpty()) {
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
        }
        else {
            MethodInvocation invocation =
                    new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
            // 构造增强器链,执行增强器的逻辑
            retVal = invocation.proceed();
        }
        // 返回值的处理 ......
        return retVal;
    } // finally ......
}

先看下面的部分,是不是跟上面 CglibAopProxy 完全一致?所以 这两者其实在底层实现中都是一样的,包括这里它创建的直接就是 ReflectiveMethodInvocation ,与上面咱看到的那个家伙是同一个。

所以这个逻辑也是一模一样的吧,具体流程这个就留给小伙伴当课后作业了,小册只在这里附一张类似的流程图啦:

Spring AOP原理-代理对象的底层执行逻辑

3. Aspect中的四种通知在源码中的实现

最后,咱对 AspectJ 中提到的四种声明式的通知,它的底层实现有一个简单的了解,前面咱看过环绕通知了,所以这个咱就不列出来了。

3.1 @Before

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
	private MethodBeforeAdvice advice;

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
		return mi.proceed();
	}
}

先执行前置通知,再执行目标方法。

3.2 @After

public class AspectJAfterAdvice extends AbstractAspectJAdvice
		implements MethodInterceptor, AfterAdvice, Serializable {

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		try {
			return mi.proceed();
		}
		finally {
			invokeAdviceMethod(getJoinPointMatch(), null, null);
		}
	}
}

执行目标方法后,在 finally 中执行后置方法(由此也说明了它的通知时机更靠后)。

3.3 @AfterReturning

public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {
	private final AfterReturningAdvice advice;

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		Object retVal = mi.proceed();
		this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
		return retVal;
	}
}

返回值后置处理中不设置 try-catch 块,说明不出现任何异常时才会触发该后置通知。

3.4 @AfterThrowing

public class AspectJAfterThrowingAdvice extends AbstractAspectJAdvice
		implements MethodInterceptor, AfterAdvice, Serializable {

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		try {
			return mi.proceed();
		}
		catch (Throwable ex) {
			if (shouldInvokeOnThrowing(ex)) {
				invokeAdviceMethod(getJoinPointMatch(), null, ex);
			}
			throw ex;
		}
	}
}

出现异常时,进入该后置通知,因为设置了 try-catch ,所以这里 catch 中根据是否标注了异常通知,进行相应的后置处理。

代理对象已经创建好了,接下来就到了正常的业务代码执行了。经过 AOP 的增强后,获取到目标对象的代理对象执行方法时,就会先执行 AOP 增强中的增强器逻辑。下面咱继续以 com.linkedbear.spring.aop.b_aspectj.AnnotationAspectJApplication 中的代码来测试,执行 financeService.addMoney 方法和 orderService.getOrderById 方法的底层逻辑。

1. FinanceService#addMoney

将断点打在 addMoney 方法的调用上,Debug 进入时,会发现它先来到了 CglibAopProxy 的内部类 DynamicAdvisedInterceptor 中:(下面的源码有点长,小册把不太重要的注释都删掉,只留下重要的几个环节,小伙伴们注意留意)

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 {
        // 如果有在@EnableAspectJAutoProxy注解上配置exposeProxy属性为true,
        // 则会把当前代理对象放入AOP上下文中
        if (this.advised.exposeProxy) {
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }
        // 从TargetSource中取出目标对象
        target = targetSource.getTarget();
        Class<?> targetClass = (target != null ? target.getClass() : null);
        // 根据当前执行的方法,获取要执行的增强器,并以列表返回(链的思想)
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
        Object retVal;
        
        // 如果没有要执行的增强器,则直接执行目标方法
        if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            retVal = methodProxy.invoke(target, argsToUse);
        }
        else {
            // 否则,构造增强器链,执行增强器的逻辑
            retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
        }
        retVal = processReturnType(proxy, target, method, retVal);
        return retVal;
    } // finally ......
}

整个流程下来,核心步骤就两步:获取增强器链、执行增强器。同时这里也发现了之前咱讲过的一些小细节:exposeProxy 的实现、TargetSource 的使用等等。不过我们最需要关注的还是这两个核心部分,咱分别来研究。

1.1 getInterceptorsAndDynamicInterceptionAdvice

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
    MethodCacheKey cacheKey = new MethodCacheKey(method);
    List<Object> cached = this.methodCache.get(cacheKey);
    if (cached == null) {
        // 核心逻辑
        cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
                this, method, targetClass);
        this.methodCache.put(cacheKey, cached);
    }
    return cached;
}

很明显又是缓存的设计,第一次调用完成后,以后就直接从缓存中读了,不需要多次获取和解析。刨去这个不看,核心的方法还是 if 结构中的方法了,咱继续往里进。不过里面的逻辑有点长,咱拆开分段研究:

1.1.1 前置准备

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
        Advised config, Method method, @Nullable Class<?> targetClass) {
    // 增强器适配器的注册器,它会根据增强器来解析,返回拦截器数组
    AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
    Advisor[] advisors = config.getAdvisors();
    List<Object> interceptorList = new ArrayList<>(advisors.length);
    Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
    Boolean hasIntroductions = null;
    // ......

在循环处理增强器之前,这里先进行了一些基本的前置处理,这里它初始化了一个 AdvisorAdapterRegistry ,意为增强器适配器的注册器,它的主要作用是将 AspectJ 类型的增强器,转换为 MethodInterceptor ( AOP 联盟的那个 MethodInterceptor )并返回。此举的目的,会在接下来的 CglibMethodInvocation 中得以体现,咱这里先有个印象即可。

Debug 到此处,发现这里面有 3 个增强器的适配器,虽然没法 toString ,但看这个名也就知道,这大概就是 Logger 那个切面类中的那几个方法。

Spring AOP原理-代理对象的底层执行逻辑

1.1.2 匹配增强器

这部分开始循环匹配增强器了:

    // ......
    for (Advisor advisor : advisors) {
        if (advisor instanceof PointcutAdvisor) {
            // 此处拿到的就是AspectJ形式的通知方法封装
            PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
            if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                // 根据通知方法上的切入点表达式,判断是否可以匹配当前要执行的目标对象所属类
                MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                boolean match;
                // 引介匹配
                if (mm instanceof IntroductionAwareMethodMatcher) {
                    if (hasIntroductions == null) {
                        hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
                    }
                    match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
                }
                else {
                    // 方法匹配
                    match = mm.matches(method, actualClass);
                }
                // ......

这部分的匹配逻辑也不难,它会把上面取出来的增强器依次与当前正在调用的目标对象做匹配,匹配的方式与之前一样,都是借助 MethodMatcher 进行。

Debug 可以发现此处把 Logger 中声明的 5 个通知方法,以及 SpringFramework 内置的那个增强器,一起都收集到了:

Spring AOP原理-代理对象的底层执行逻辑

1.1.3 匹配后的处理

匹配到增强器之后,接下来就是决定如何封装为 MethodInterceptor 了:

                // ......
                if (match) {
                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                    // runtime的概念
                    if (mm.isRuntime()) {
                        for (MethodInterceptor interceptor : interceptors) {
                            interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                        }
                    } else {
                        interceptorList.addAll(Arrays.asList(interceptors));
                    }
                }
            }
        }
        // ......

这部分本身的添加并不难,不过这里面有一个 runtime 的概念,想必小伙伴们会比较懵,这里咱简单解释一下。

通常情况下,MethodMatcher 都是静态的匹配器,但 Spring 在此处做了一个设计,如果 MethodMatcher 被设置为动态的匹配器,则每次调用匹配方法时,可以提前拿到方法调用的参数值列表。说起来有点难理解,咱先看两个方法的签名:

boolean matches(Method method, Class<?> targetClass);

boolean matches(Method method, Class<?> targetClass, Object... args);

小册这样解释一下,你们都就立马明白了:静态匹配器只会做匹配,而动态的匹配器可以提前拿到方法调用的参数值列表(注意是参数值)。

1.1.4 其他增强器的处理

        // ......
        else if (advisor instanceof IntroductionAdvisor) {
            IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
            if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
                Interceptor[] interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        }
        else {
            Interceptor[] interceptors = registry.getInterceptors(advisor);
            interceptorList.addAll(Arrays.asList(interceptors));
        }
    }

    return interceptorList;
}

在最下面,就是引介增强器,以及其它类型的增强器的处理了,这里咱一般都碰不到,AspectJ 风格的声明都是走上面的 PointcutAdvisor 判断逻辑,所以咱这里就不细展开了。

经过这个方法的处理之后,当前目标对象要执行的方法就都筛选出来了,接下来就是构建方法执行器了。

1.2 CglibMethodInvocation

下面是构造的 CglibMethodInvocation ,执行 proceed 方法了,咱先看看这个 CglibMethodInvocation 是个啥:

private static class CglibMethodInvocation extends ReflectiveMethodInvocation
public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable
public interface ProxyMethodInvocation extends MethodInvocation

得了,果然还是回到 AOP 联盟定义的那个 MethodInvocation 了,那咱就知道上面的那个适配的设计了,大家都是 MethodInvocation ,那就都好说了。

接下来,咱执行 proceed 方法,而在 CglibMethodInvocation 中,它只是单纯的调用父类的 proceed 方法:

public Object proceed() throws Throwable {
    try {
        return super.proceed();
    } // catch ......
}

那往上调用,那就来到 ReflectiveMethodInvocation 类中了。

接下来的调用过程可能会很绕,小册尝试用过程的方式记录每一步的执行动作和逻辑,方便小伙伴们体会这里面的高深设计。

1.2.0 方法概览

先大概看一下 proceed 方法的设计吧,

protected final List<?> interceptorsAndDynamicMethodMatchers;
private int currentInterceptorIndex = -1;

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) {
        // 此处是动态匹配器构造的特殊逻辑
        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 {
            return proceed();
        }
    }
    else {
        // 此处会调用增强器的逻辑
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
}

这里先解释一波动态匹配器的逻辑,看中间的 if 部分,如果 MethodMatcher 有被封装为动态匹配器,则这里会继续匹配,如果动态匹配器在匹配到方法调用的参数值列表发现匹配不上,则这个增强器不会执行。

其余的部分,就看接下来的执行逻辑咯,小伙伴们不要被小册搞晕哦。

1.2.1 执行proceed方法

public Object proceed() throws Throwable {
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return invokeJoinpoint();
    }

此时的 currentInterceptorIndex 下标值为 -1 :

Spring AOP原理-代理对象的底层执行逻辑

计算值:-1 ≠ 3 - 1,则不进入 invokeJoinpoint 方法,继续往下走。

1.2.2 下标值++

接下来,执行下面的 this.interceptorsAndDynamicMethodMatchers.get 动作,此时 this.currentInterceptorIndex 执行了一次自增操作:

    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return invokeJoinpoint();
    }

    Object interceptorOrInterceptionAdvice =
            this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {

此时 currentInterceptorIndex 值为 0 。

1.2.3 执行第一个增强器

既然获取到了增强器对应的拦截器,那就执行它:

public Object invoke(MethodInvocation mi) throws Throwable {
    MethodInvocation oldInvocation = invocation.get();
    invocation.set(mi);
    try {
        return mi.proceed();
    }
    finally {
        invocation.set(oldInvocation);
    }
}

又看到这个 invoke 方法了,咱已经挺熟悉了,下一步肯定是继续执行 proceed 方法嘛。

1.2.4 继续执行proceed方法

接下来执行 proceed 方法,会发现它又回到上面的 1.2.1 步了,只不过此时的 currentInterceptorIndex 值不再是 -1 ,而是 0 。

Spring AOP原理-代理对象的底层执行逻辑

计算值:0 ≠ 3 - 1,则不进入 invokeJoinpoint 方法,继续往下走。

1.2.5 进入AspectJAroundAdvice中

那既然计算结果不等,那就继续执行增强器逻辑嘛,由于接下来要执行的是一个环绕通知,咱来到 AspectJAroundAdvice 的 invoke 方法中:

public Object invoke(MethodInvocation mi) throws Throwable {
    if (!(mi instanceof ProxyMethodInvocation)) {
        throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
    }
    ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
    ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
    JoinPointMatch jpm = getJoinPointMatch(pmi);
    return invokeAdviceMethod(pjp, jpm, null, null);
}

前面的获取都是很基本的了,最下面的 invokeAdviceMethod 才是关键:

protected Object invokeAdviceMethod(JoinPoint jp, @Nullable JoinPointMatch jpMatch,
        @Nullable Object returnValue, @Nullable Throwable t) throws Throwable {
    return invokeAdviceMethodWithGivenArgs(argBinding(jp, jpMatch, returnValue, t));
}

protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
    Object[] actualArgs = args;
    if (this.aspectJAdviceMethod.getParameterCount() == 0) {
        actualArgs = null;
    }
    try {
        ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
        return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
    } // catch ......
}

合着折腾到最后,还是个反射执行目标对象的方法。。。

1.2.6 进入到Logger中

因为是环绕通知嘛,那就理所应当的进入到 Logger 中了:

@Around("execution(public * com.linkedbear.spring.aop.b_aspectj.service.FinanceService.addMoney(..))")
public Object aroundPrint(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("Logger aroundPrint before run ......");
    try {
        Object retVal = joinPoint.proceed();
        System.out.println("Logger aroundPrint afterReturning run ......");
        return retVal;
    } // catch finally ......
}

执行了前置通知打印后,接下来的 joinPoint.proceed 方法的执行,想必不用小册解释,小伙伴们也能想得到了吧。

1.2.7 继续执行proceed方法

想是想到了,但这个中间还有个小插曲。。。proceed 方法的执行,肯定是走的 ProceedingJoinPoint 的 proceed 方法呀,不是上面 ReflectiveMethodInvocation 的:

public Object proceed() throws Throwable {
    return this.methodInvocation.invocableClone().proceed();
}

哎,这里的 proceed 方法,才是上面咱执行那些 proceed 方法,此时 currentInterceptorIndex 的值为 1 :

Spring AOP原理-代理对象的底层执行逻辑

然后,又是同样的获取、自增、执行。。。

1.2.8 进入MethodBeforeAdviceInterceptor中

第三个通知方法的执行,是那个前置通知,它会来到 MethodBeforeAdviceInterceptor 中:

public Object invoke(MethodInvocation mi) throws Throwable {
    this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
    return mi.proceed();
}

可以发现还蛮简单的,它就是把前置通知的方法执行一下,然后继续执行 MethodInvocation 的 proceed 方法了。

1.2.9 执行目标对象方法

接下来,又回到 proceed 方法,此时 currentInterceptorIndex 的值为 2 :

计算得 2 = 3 - 1 ,终于相等了,那就可以执行目标方法了。

1.2.10 流程小结

好了,经过这个流程之后,咱终于走完这个全程,由此我们可以得出算法逻辑:

利用一个全局索引值,决定每次执行的拦截器,当所有拦截器都执行完时,索引值刚好等于 size() - 1,此时就可以执行真正的目标方法了 。

最后用一张图来更好地理解这段逻辑:

Spring AOP原理-代理对象的底层执行逻辑

2. OrderService#getOrderById

咱继续研究 jdk 动态代理的执行。将断点打在 getOrderById 方法的调用上,Debug 进入时它肯定就不跟上面的 Cglib 动态代理一样了,它进入的是 JdkDynamicAopProxy 中。不过由于这里面的 invoke 方法实在是有点长,小册在这里只截取关键部分:

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

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

    try {
        // equals方法不代理
        if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
            // The target does not implement the equals(Object) method itself.
            return equals(args[0]);
        }
        // hashCode方法不代理
        else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
            // The target does not implement the hashCode() method itself.
            return hashCode();
        }
        // 方法来自于DecoratingProxy接口的,也不代理
        else if (method.getDeclaringClass() == DecoratingProxy.class) {
            // There is only getDecoratedClass() declared -> dispatch to proxy config.
            return AopProxyUtils.ultimateTargetClass(this.advised);
        }
        // 目标对象本身就是实现了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) {
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }

        target = targetSource.getTarget();
        Class<?> targetClass = (target != null ? target.getClass() : null);

        // 根据当前执行的方法,获取要执行的增强器,并以列表返回(链的思想)
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
        if (chain.isEmpty()) {
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
        }
        else {
            MethodInvocation invocation =
                    new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
            // 构造增强器链,执行增强器的逻辑
            retVal = invocation.proceed();
        }
        // 返回值的处理 ......
        return retVal;
    } // finally ......
}

先看下面的部分,是不是跟上面 CglibAopProxy 完全一致?所以 这两者其实在底层实现中都是一样的,包括这里它创建的直接就是 ReflectiveMethodInvocation ,与上面咱看到的那个家伙是同一个。

所以这个逻辑也是一模一样的吧,具体流程这个就留给小伙伴当课后作业了,小册只在这里附一张类似的流程图啦:

Spring AOP原理-代理对象的底层执行逻辑

3. Aspect中的四种通知在源码中的实现

最后,咱对 AspectJ 中提到的四种声明式的通知,它的底层实现有一个简单的了解,前面咱看过环绕通知了,所以这个咱就不列出来了。

3.1 @Before

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
	private MethodBeforeAdvice advice;

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
		return mi.proceed();
	}
}

先执行前置通知,再执行目标方法。

3.2 @After

public class AspectJAfterAdvice extends AbstractAspectJAdvice
		implements MethodInterceptor, AfterAdvice, Serializable {

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		try {
			return mi.proceed();
		}
		finally {
			invokeAdviceMethod(getJoinPointMatch(), null, null);
		}
	}
}

执行目标方法后,在 finally 中执行后置方法(由此也说明了它的通知时机更靠后)。

3.3 @AfterReturning

public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {
	private final AfterReturningAdvice advice;

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		Object retVal = mi.proceed();
		this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
		return retVal;
	}
}

返回值后置处理中不设置 try-catch 块,说明不出现任何异常时才会触发该后置通知。

3.4 @AfterThrowing

public class AspectJAfterThrowingAdvice extends AbstractAspectJAdvice
		implements MethodInterceptor, AfterAdvice, Serializable {

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		try {
			return mi.proceed();
		}
		catch (Throwable ex) {
			if (shouldInvokeOnThrowing(ex)) {
				invokeAdviceMethod(getJoinPointMatch(), null, ex);
			}
			throw ex;
		}
	}
}

出现异常时,进入该后置通知,因为设置了 try-catch ,所以这里 catch 中根据是否标注了异常通知,进行相应的后置处理。

代理对象已经创建好了,接下来就到了正常的业务代码执行了。经过 AOP 的增强后,获取到目标对象的代理对象执行方法时,就会先执行 AOP 增强中的增强器逻辑。下面咱继续以 com.linkedbear.spring.aop.b_aspectj.AnnotationAspectJApplication 中的代码来测试,执行 financeService.addMoney 方法和 orderService.getOrderById 方法的底层逻辑。

1. FinanceService#addMoney

将断点打在 addMoney 方法的调用上,Debug 进入时,会发现它先来到了 CglibAopProxy 的内部类 DynamicAdvisedInterceptor 中:(下面的源码有点长,小册把不太重要的注释都删掉,只留下重要的几个环节,小伙伴们注意留意)

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 {
        // 如果有在@EnableAspectJAutoProxy注解上配置exposeProxy属性为true,
        // 则会把当前代理对象放入AOP上下文中
        if (this.advised.exposeProxy) {
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }
        // 从TargetSource中取出目标对象
        target = targetSource.getTarget();
        Class<?> targetClass = (target != null ? target.getClass() : null);
        // 根据当前执行的方法,获取要执行的增强器,并以列表返回(链的思想)
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
        Object retVal;
        
        // 如果没有要执行的增强器,则直接执行目标方法
        if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            retVal = methodProxy.invoke(target, argsToUse);
        }
        else {
            // 否则,构造增强器链,执行增强器的逻辑
            retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
        }
        retVal = processReturnType(proxy, target, method, retVal);
        return retVal;
    } // finally ......
}

整个流程下来,核心步骤就两步:获取增强器链、执行增强器。同时这里也发现了之前咱讲过的一些小细节:exposeProxy 的实现、TargetSource 的使用等等。不过我们最需要关注的还是这两个核心部分,咱分别来研究。

1.1 getInterceptorsAndDynamicInterceptionAdvice

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
    MethodCacheKey cacheKey = new MethodCacheKey(method);
    List<Object> cached = this.methodCache.get(cacheKey);
    if (cached == null) {
        // 核心逻辑
        cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
                this, method, targetClass);
        this.methodCache.put(cacheKey, cached);
    }
    return cached;
}

很明显又是缓存的设计,第一次调用完成后,以后就直接从缓存中读了,不需要多次获取和解析。刨去这个不看,核心的方法还是 if 结构中的方法了,咱继续往里进。不过里面的逻辑有点长,咱拆开分段研究:

1.1.1 前置准备

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
        Advised config, Method method, @Nullable Class<?> targetClass) {
    // 增强器适配器的注册器,它会根据增强器来解析,返回拦截器数组
    AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
    Advisor[] advisors = config.getAdvisors();
    List<Object> interceptorList = new ArrayList<>(advisors.length);
    Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
    Boolean hasIntroductions = null;
    // ......

在循环处理增强器之前,这里先进行了一些基本的前置处理,这里它初始化了一个 AdvisorAdapterRegistry ,意为增强器适配器的注册器,它的主要作用是将 AspectJ 类型的增强器,转换为 MethodInterceptor ( AOP 联盟的那个 MethodInterceptor )并返回。此举的目的,会在接下来的 CglibMethodInvocation 中得以体现,咱这里先有个印象即可。

Debug 到此处,发现这里面有 3 个增强器的适配器,虽然没法 toString ,但看这个名也就知道,这大概就是 Logger 那个切面类中的那几个方法。

Spring AOP原理-代理对象的底层执行逻辑

1.1.2 匹配增强器

这部分开始循环匹配增强器了:

    // ......
    for (Advisor advisor : advisors) {
        if (advisor instanceof PointcutAdvisor) {
            // 此处拿到的就是AspectJ形式的通知方法封装
            PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
            if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                // 根据通知方法上的切入点表达式,判断是否可以匹配当前要执行的目标对象所属类
                MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                boolean match;
                // 引介匹配
                if (mm instanceof IntroductionAwareMethodMatcher) {
                    if (hasIntroductions == null) {
                        hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
                    }
                    match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
                }
                else {
                    // 方法匹配
                    match = mm.matches(method, actualClass);
                }
                // ......

这部分的匹配逻辑也不难,它会把上面取出来的增强器依次与当前正在调用的目标对象做匹配,匹配的方式与之前一样,都是借助 MethodMatcher 进行。

Debug 可以发现此处把 Logger 中声明的 5 个通知方法,以及 SpringFramework 内置的那个增强器,一起都收集到了:

Spring AOP原理-代理对象的底层执行逻辑

1.1.3 匹配后的处理

匹配到增强器之后,接下来就是决定如何封装为 MethodInterceptor 了:

                // ......
                if (match) {
                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                    // runtime的概念
                    if (mm.isRuntime()) {
                        for (MethodInterceptor interceptor : interceptors) {
                            interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                        }
                    } else {
                        interceptorList.addAll(Arrays.asList(interceptors));
                    }
                }
            }
        }
        // ......

这部分本身的添加并不难,不过这里面有一个 runtime 的概念,想必小伙伴们会比较懵,这里咱简单解释一下。

通常情况下,MethodMatcher 都是静态的匹配器,但 Spring 在此处做了一个设计,如果 MethodMatcher 被设置为动态的匹配器,则每次调用匹配方法时,可以提前拿到方法调用的参数值列表。说起来有点难理解,咱先看两个方法的签名:

boolean matches(Method method, Class<?> targetClass);

boolean matches(Method method, Class<?> targetClass, Object... args);

小册这样解释一下,你们都就立马明白了:静态匹配器只会做匹配,而动态的匹配器可以提前拿到方法调用的参数值列表(注意是参数值)。

1.1.4 其他增强器的处理

        // ......
        else if (advisor instanceof IntroductionAdvisor) {
            IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
            if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
                Interceptor[] interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        }
        else {
            Interceptor[] interceptors = registry.getInterceptors(advisor);
            interceptorList.addAll(Arrays.asList(interceptors));
        }
    }

    return interceptorList;
}

在最下面,就是引介增强器,以及其它类型的增强器的处理了,这里咱一般都碰不到,AspectJ 风格的声明都是走上面的 PointcutAdvisor 判断逻辑,所以咱这里就不细展开了。

经过这个方法的处理之后,当前目标对象要执行的方法就都筛选出来了,接下来就是构建方法执行器了。

1.2 CglibMethodInvocation

下面是构造的 CglibMethodInvocation ,执行 proceed 方法了,咱先看看这个 CglibMethodInvocation 是个啥:

private static class CglibMethodInvocation extends ReflectiveMethodInvocation
public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable
public interface ProxyMethodInvocation extends MethodInvocation

得了,果然还是回到 AOP 联盟定义的那个 MethodInvocation 了,那咱就知道上面的那个适配的设计了,大家都是 MethodInvocation ,那就都好说了。

接下来,咱执行 proceed 方法,而在 CglibMethodInvocation 中,它只是单纯的调用父类的 proceed 方法:

public Object proceed() throws Throwable {
    try {
        return super.proceed();
    } // catch ......
}

那往上调用,那就来到 ReflectiveMethodInvocation 类中了。

接下来的调用过程可能会很绕,小册尝试用过程的方式记录每一步的执行动作和逻辑,方便小伙伴们体会这里面的高深设计。

1.2.0 方法概览

先大概看一下 proceed 方法的设计吧,

protected final List<?> interceptorsAndDynamicMethodMatchers;
private int currentInterceptorIndex = -1;

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) {
        // 此处是动态匹配器构造的特殊逻辑
        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 {
            return proceed();
        }
    }
    else {
        // 此处会调用增强器的逻辑
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
}

这里先解释一波动态匹配器的逻辑,看中间的 if 部分,如果 MethodMatcher 有被封装为动态匹配器,则这里会继续匹配,如果动态匹配器在匹配到方法调用的参数值列表发现匹配不上,则这个增强器不会执行。

其余的部分,就看接下来的执行逻辑咯,小伙伴们不要被小册搞晕哦。

1.2.1 执行proceed方法

public Object proceed() throws Throwable {
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return invokeJoinpoint();
    }

此时的 currentInterceptorIndex 下标值为 -1 :

Spring AOP原理-代理对象的底层执行逻辑

计算值:-1 ≠ 3 - 1,则不进入 invokeJoinpoint 方法,继续往下走。

1.2.2 下标值++

接下来,执行下面的 this.interceptorsAndDynamicMethodMatchers.get 动作,此时 this.currentInterceptorIndex 执行了一次自增操作:

    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return invokeJoinpoint();
    }

    Object interceptorOrInterceptionAdvice =
            this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {

此时 currentInterceptorIndex 值为 0 。

1.2.3 执行第一个增强器

既然获取到了增强器对应的拦截器,那就执行它:

public Object invoke(MethodInvocation mi) throws Throwable {
    MethodInvocation oldInvocation = invocation.get();
    invocation.set(mi);
    try {
        return mi.proceed();
    }
    finally {
        invocation.set(oldInvocation);
    }
}

又看到这个 invoke 方法了,咱已经挺熟悉了,下一步肯定是继续执行 proceed 方法嘛。

1.2.4 继续执行proceed方法

接下来执行 proceed 方法,会发现它又回到上面的 1.2.1 步了,只不过此时的 currentInterceptorIndex 值不再是 -1 ,而是 0 。

Spring AOP原理-代理对象的底层执行逻辑

计算值:0 ≠ 3 - 1,则不进入 invokeJoinpoint 方法,继续往下走。

1.2.5 进入AspectJAroundAdvice中

那既然计算结果不等,那就继续执行增强器逻辑嘛,由于接下来要执行的是一个环绕通知,咱来到 AspectJAroundAdvice 的 invoke 方法中:

public Object invoke(MethodInvocation mi) throws Throwable {
    if (!(mi instanceof ProxyMethodInvocation)) {
        throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
    }
    ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
    ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
    JoinPointMatch jpm = getJoinPointMatch(pmi);
    return invokeAdviceMethod(pjp, jpm, null, null);
}

前面的获取都是很基本的了,最下面的 invokeAdviceMethod 才是关键:

protected Object invokeAdviceMethod(JoinPoint jp, @Nullable JoinPointMatch jpMatch,
        @Nullable Object returnValue, @Nullable Throwable t) throws Throwable {
    return invokeAdviceMethodWithGivenArgs(argBinding(jp, jpMatch, returnValue, t));
}

protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
    Object[] actualArgs = args;
    if (this.aspectJAdviceMethod.getParameterCount() == 0) {
        actualArgs = null;
    }
    try {
        ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
        return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
    } // catch ......
}

合着折腾到最后,还是个反射执行目标对象的方法。。。

1.2.6 进入到Logger中

因为是环绕通知嘛,那就理所应当的进入到 Logger 中了:

@Around("execution(public * com.linkedbear.spring.aop.b_aspectj.service.FinanceService.addMoney(..))")
public Object aroundPrint(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("Logger aroundPrint before run ......");
    try {
        Object retVal = joinPoint.proceed();
        System.out.println("Logger aroundPrint afterReturning run ......");
        return retVal;
    } // catch finally ......
}

执行了前置通知打印后,接下来的 joinPoint.proceed 方法的执行,想必不用小册解释,小伙伴们也能想得到了吧。

1.2.7 继续执行proceed方法

想是想到了,但这个中间还有个小插曲。。。proceed 方法的执行,肯定是走的 ProceedingJoinPoint 的 proceed 方法呀,不是上面 ReflectiveMethodInvocation 的:

public Object proceed() throws Throwable {
    return this.methodInvocation.invocableClone().proceed();
}

哎,这里的 proceed 方法,才是上面咱执行那些 proceed 方法,此时 currentInterceptorIndex 的值为 1 :

Spring AOP原理-代理对象的底层执行逻辑

然后,又是同样的获取、自增、执行。。。

1.2.8 进入MethodBeforeAdviceInterceptor中

第三个通知方法的执行,是那个前置通知,它会来到 MethodBeforeAdviceInterceptor 中:

public Object invoke(MethodInvocation mi) throws Throwable {
    this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
    return mi.proceed();
}

可以发现还蛮简单的,它就是把前置通知的方法执行一下,然后继续执行 MethodInvocation 的 proceed 方法了。

1.2.9 执行目标对象方法

接下来,又回到 proceed 方法,此时 currentInterceptorIndex 的值为 2 :

计算得 2 = 3 - 1 ,终于相等了,那就可以执行目标方法了。

1.2.10 流程小结

好了,经过这个流程之后,咱终于走完这个全程,由此我们可以得出算法逻辑:

利用一个全局索引值,决定每次执行的拦截器,当所有拦截器都执行完时,索引值刚好等于 size() - 1,此时就可以执行真正的目标方法了 。

最后用一张图来更好地理解这段逻辑:

Spring AOP原理-代理对象的底层执行逻辑

2. OrderService#getOrderById

咱继续研究 jdk 动态代理的执行。将断点打在 getOrderById 方法的调用上,Debug 进入时它肯定就不跟上面的 Cglib 动态代理一样了,它进入的是 JdkDynamicAopProxy 中。不过由于这里面的 invoke 方法实在是有点长,小册在这里只截取关键部分:

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

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

    try {
        // equals方法不代理
        if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
            // The target does not implement the equals(Object) method itself.
            return equals(args[0]);
        }
        // hashCode方法不代理
        else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
            // The target does not implement the hashCode() method itself.
            return hashCode();
        }
        // 方法来自于DecoratingProxy接口的,也不代理
        else if (method.getDeclaringClass() == DecoratingProxy.class) {
            // There is only getDecoratedClass() declared -> dispatch to proxy config.
            return AopProxyUtils.ultimateTargetClass(this.advised);
        }
        // 目标对象本身就是实现了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) {
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }

        target = targetSource.getTarget();
        Class<?> targetClass = (target != null ? target.getClass() : null);

        // 根据当前执行的方法,获取要执行的增强器,并以列表返回(链的思想)
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
        if (chain.isEmpty()) {
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
        }
        else {
            MethodInvocation invocation =
                    new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
            // 构造增强器链,执行增强器的逻辑
            retVal = invocation.proceed();
        }
        // 返回值的处理 ......
        return retVal;
    } // finally ......
}

先看下面的部分,是不是跟上面 CglibAopProxy 完全一致?所以 这两者其实在底层实现中都是一样的,包括这里它创建的直接就是 ReflectiveMethodInvocation ,与上面咱看到的那个家伙是同一个。

所以这个逻辑也是一模一样的吧,具体流程这个就留给小伙伴当课后作业了,小册只在这里附一张类似的流程图啦:

Spring AOP原理-代理对象的底层执行逻辑

3. Aspect中的四种通知在源码中的实现

最后,咱对 AspectJ 中提到的四种声明式的通知,它的底层实现有一个简单的了解,前面咱看过环绕通知了,所以这个咱就不列出来了。

3.1 @Before

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
	private MethodBeforeAdvice advice;

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
		return mi.proceed();
	}
}

先执行前置通知,再执行目标方法。

3.2 @After

public class AspectJAfterAdvice extends AbstractAspectJAdvice
		implements MethodInterceptor, AfterAdvice, Serializable {

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		try {
			return mi.proceed();
		}
		finally {
			invokeAdviceMethod(getJoinPointMatch(), null, null);
		}
	}
}

执行目标方法后,在 finally 中执行后置方法(由此也说明了它的通知时机更靠后)。

3.3 @AfterReturning

public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {
	private final AfterReturningAdvice advice;

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		Object retVal = mi.proceed();
		this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
		return retVal;
	}
}

返回值后置处理中不设置 try-catch 块,说明不出现任何异常时才会触发该后置通知。

3.4 @AfterThrowing

public class AspectJAfterThrowingAdvice extends AbstractAspectJAdvice
		implements MethodInterceptor, AfterAdvice, Serializable {

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		try {
			return mi.proceed();
		}
		catch (Throwable ex) {
			if (shouldInvokeOnThrowing(ex)) {
				invokeAdviceMethod(getJoinPointMatch(), null, ex);
			}
			throw ex;
		}
	}
}

出现异常时,进入该后置通知,因为设置了 try-catch ,所以这里 catch 中根据是否标注了异常通知,进行相应的后置处理。

 

免责声明:
1.本站所有内容由本站原创、网络转载、消息撰写、网友投稿等几部分组成。
2.本站原创文字内容若未经特别声明,则遵循协议CC3.0共享协议,转载请务必注明原文链接。
3.本站部分来源于网络转载的文章信息是出于传递更多信息之目的,不意味着赞同其观点。
4.本站所有源码与软件均为原作者提供,仅供学习和研究使用。
5.如您对本网站的相关版权有任何异议,或者认为侵犯了您的合法权益,请及时通知我们处理。
火焰兔 » Spring AOP原理-代理对象的底层执行逻辑