前言

本篇文章是SpringAOP的源码学习分享,分为高低两篇,上篇已知SpringAOP的切面类织入业务bean后,会为业务bean生成动静代理对象,这个动静代理对象中持有须要失效的所有告诉,叫做告诉链。本篇将对调用AOP动静代理对象时的整个流程进行学习,以探索切面中的相似于前置告诉或者后置告诉这种告诉办法是如何对指标bean的指标办法进行加强的。

注:本文均基于JDK动静代理。

注释

一. AOP动静代理对象构造剖析

在上篇的示例工程中,能够看一下测试程序中从容器获取到的IMyServicebean是什么样子,调试图如下所示。

能够看到获取进去的bean理论为MyServiceJDK动静代理对象,InvocationHandlerJdkDynamicAopProxyJdkDynamicAopProxy中持有ProxyFactoryProxyFactory中持有指标对象和告诉链。

二. AOP动静代理对象调用剖析

调用动静代理对象的办法时,会调用到InvocationHandlerinvoke()办法,这里InvocationHandlerJdkDynamicAopProxy,所以将JdkDynamicAopProxyinvoke()办法作为入口开始剖析。

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 {        if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {            //不会将告诉作用在equals()办法,除非指标对象实现的接口中定义了equals()办法            return equals(args[0]);        }        else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {            //不会将告诉作用在hashCode()办法,除非指标对象实现的接口中定义了hashCode()办法            return hashCode();        }        else if (method.getDeclaringClass() == DecoratingProxy.class) {            return AopProxyUtils.ultimateTargetClass(this.advised);        }        else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&                method.getDeclaringClass().isAssignableFrom(Advised.class)) {            //不会将告诉作用于Advised接口或者其父接口中定义的办法            return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);        }        Object retVal;        if (this.advised.exposeProxy) {            oldProxy = AopContext.setCurrentProxy(proxy);            setProxyContext = true;        }        //获取指标对象        target = targetSource.getTarget();        //获取指标对象的Class对象        Class<?> targetClass = (target != null ? target.getClass() : null);        //将告诉链中可能作用于以后办法的告诉组装成拦截器链        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);        if (chain.isEmpty()) {            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);            //如果拦截器链是空,那么间接调用指标对象办法            //AopUtils.invokeJoinpointUsingReflection()最终会调用到method.invoke(target, args)            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);        }        else {            //创立办法调用器MethodInvocation,理论为ReflectiveMethodInvocation            //创立ReflectiveMethodInvocation时传入的参数顺次为:代理对象,指标对象,指标办法,指标办法参数,指标对象的Class对象,拦截器链            MethodInvocation invocation =                    new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);            //调用办法调用器的proceed()办法,开始进入调用各个告诉办法和指标办法的递归流程            retVal = invocation.proceed();        }        Class<?> returnType = method.getReturnType();        if (retVal != null && retVal == target &&                returnType != Object.class && returnType.isInstance(proxy) &&                !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {            retVal = proxy;        }        else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {            throw new AopInvocationException(                    "Null return value from advice does not match primitive return type for: " + method);        }        return retVal;    }    finally {        if (target != null && !targetSource.isStatic()) {            targetSource.releaseTarget(target);        }        if (setProxyContext) {            AopContext.setCurrentProxy(oldProxy);        }    }}

上述的invoke()办法次要是做了两件事件,第一件事件是将告诉链中所有可能作用于以后指标办法的告诉构建成拦截器链,并基于拦截器链生成办法调用器ReflectiveMethodInvocation,第二件事件就是调用ReflectiveMethodInvocationproceed()办法,这个办法会调用到指标办法,并且在调用的过程中,拦截器链中的拦截器也会执行以达到加强性能的成果。上面先看一下告诉链如何构建成拦截器链,this.advised理论就是生成动静代理对象的时候的ProxyFactory,而ProxyFactory继承于AdvisedSupport,将告诉链构建成拦截器链的办法就是AdvisedSupportgetInterceptorsAndDynamicInterceptionAdvice(),如下所示。

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {    MethodCacheKey cacheKey = new MethodCacheKey(method);    //先依据Method从缓存中拿拦截器链,缓存中没有时会去生成并缓存起来    List<Object> cached = this.methodCache.get(cacheKey);    if (cached == null) {        //理论调用到DefaultAdvisorChainFactory的getInterceptorsAndDynamicInterceptionAdvice()办法来生成拦截器链        cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(                this, method, targetClass);        this.methodCache.put(cacheKey, cached);    }    return cached;}

每个指标办法对应的拦截器链在生成后都会被缓存,所以会先从缓存中拿拦截器链,缓存中没有时会去调用DefaultAdvisorChainFactorygetInterceptorsAndDynamicInterceptionAdvice()办法来生成拦截器链,getInterceptorsAndDynamicInterceptionAdvice()办法实现如下。

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(        Advised config, Method method, @Nullable Class<?> targetClass) {    AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();    //先从ProxyFactory中将告诉链获取进去    Advisor[] advisors = config.getAdvisors();    List<Object> interceptorList = new ArrayList<>(advisors.length);    Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());    Boolean hasIntroductions = null;    for (Advisor advisor : advisors) {        //因为Advisor接口有两个子类接口,别离是PointcutAdvisor和IntroductionAdvisor        if (advisor instanceof PointcutAdvisor) {            //解决PointcutAdvisor,示例中应用的都是PointcutAdvisor            PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;            if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {                //获取切点对象,这里的mm类型为AspectJExpressionPointcut                MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();                boolean match;                if (mm instanceof IntroductionAwareMethodMatcher) {                    if (hasIntroductions == null) {                        hasIntroductions = hasMatchingIntroductions(advisors, actualClass);                    }                    //判断以后Advisor是否可能作用于指标办法                    match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);                }                else {                    //判断以后Advisor是否可能作用于指标办法                    match = mm.matches(method, actualClass);                }                if (match) {                    //如果以后Advisor可能作用于指标办法,那么将以后Advisor转换为MethodInterceptor,即告诉转换为办法拦截器                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);                    if (mm.isRuntime()) {                        for (MethodInterceptor interceptor : interceptors) {                            //将办法拦截器和切点对象封装成InterceptorAndDynamicMethodMatcher并退出拦截器链中                            interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));                        }                    }                    else {                        interceptorList.addAll(Arrays.asList(interceptors));                    }                }            }        }        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;}

告诉链转换为拦截器链的过程概括如下。

  • 先从Advisor中将切点对象获取进去,并依据切点对象判断以后Advisor是否可能作用于指标办法;
  • 将可能作用于指标办法的Advisor封装成办法拦截器MethodInterceptor,并退出拦截器链。

MethodInterceptor是一个接口,定义了办法拦截器,示例中应用的前置告诉和后置告诉对应的办法拦截器别离为MethodBeforeAdviceInterceptorAspectJAfterAdvice,它们的关系能够用上面的类图示意。

拦截器链获取到后,在JdkDynamicAopProxyinvoke()办法中还会再创立一个办法调用器ReflectiveMethodInvocation,其类图如下所示。

通过类图能够晓得,ReflectiveMethodInvocation中持有代理对象,指标对象,指标办法,指标办法参数,指标对象的Class对象,拦截器链,后续调用告诉办法以及调用指标办法的逻辑的入口,就是ReflectiveMethodInvocationproceed()办法。

下面剖析了AOP动静代理对象调用时,JdkDynamicAopProxyinvoke()办法中做的第一件事件,行将告诉链中所有可能作用于以后指标办法的告诉构建成拦截器链,并基于拦截器链生成办法调用器ReflectiveMethodInvocation,上面剖析第二件事件,即调用ReflectiveMethodInvocationproceed()办法,通过调用proceed()办法能够在调用指标办法的前后将告诉的加强利用到指标办法上,上面剖析一下整个调用流程,ReflectiveMethodInvocationproceed()办法实现如下。

//currentInterceptorIndex用于批示以后须要调用的拦截器//初始为-1,每次应用前会先加1private int currentInterceptorIndex = -1;public Object proceed() throws Throwable {    //当拦截器都遍历完后,则调用指标办法    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {        //调用invokeJoinpoint()办法来执行指标办法        //invokeJoinpoint()会调用AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments),即通过反射执行指标办法        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)) {            //调用各种告诉对应的拦截器的invoke()办法            return dm.interceptor.invoke(this);        }        else {            return proceed();        }    }    else {        //拦截器是ExposeInvocationInterceptor时会调用到这里        //ExposeInvocationInterceptor的invoke()办法会先为以后线程保留办法调用器ReflectiveMethodInvocation        //而后再递归调用ReflectiveMethodInvocation的proceed()办法        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);    }}

ReflectiveMethodInvocationproceed()办法中,会顺次先调用所有拦截器的invoke()办法,最初才调用行指标办法,然而理论状况下,有一些告诉是须要在指标办法执行后或者指标办法抛出异样时才执行,所以能够揣测,调用了拦截器的invoke()办法不代表拦截器对应的告诉逻辑会被执行,以及在拦截器的invoke()办法中会在某个工夫点递归的调用回ReflectiveMethodInvocationproceed()办法。为了不便了解,上面别离的以本示例中应用到的ExposeInvocationInterceptorMethodBeforeAdviceInterceptorAspectJAfterAdvice这三种拦截器进行阐明。

  • ExposeInvocationInterceptorinvoke()办法如下所示。
public Object invoke(MethodInvocation mi) throws Throwable {    MethodInvocation oldInvocation = invocation.get();    //为以后线程保留办法调用器,即保留ReflectiveMethodInvocation    invocation.set(mi);    try {        //递归调用ReflectiveMethodInvocation的proceed()办法来执行其它拦截器或者指标办法        return mi.proceed();    }    finally {        invocation.set(oldInvocation);    }}

ExposeInvocationInterceptor只是为以后线程保留了办法调用器的援用。

  • MethodBeforeAdviceInterceptorinvoke()办法如下所示。
public Object invoke(MethodInvocation mi) throws Throwable {    //前置告诉的逻辑要先于指标办法执行,所以这里先执行前置告诉的逻辑    this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());    //递归调用ReflectiveMethodInvocation的proceed()办法来执行其它拦截器或者指标办法    return mi.proceed();}

MethodBeforeAdviceInterceptorinvoke()办法只有调用到了,那么对应的前置告诉的逻辑就会被执行,这一点合乎前置告诉在指标办法执行前执行,前置告诉逻辑执行结束后,会再调用回ReflectiveMethodInvocationproceed()办法,以便调用其它拦截器和指标办法。

  • AspectJAfterAdviceinvoke()办法如下所示。
public Object invoke(MethodInvocation mi) throws Throwable {    try {        //递归调用ReflectiveMethodInvocation的proceed()办法来先执行其它拦截器或者指标办法        return mi.proceed();    }    finally {        //后置告诉的逻辑要在指标办法执行后再执行,所以这里将后置告诉的执行放在了finally中        //也表明就算指标办法或者其它拦截器执行时抛出异样,后置告诉的逻辑也是会执行到的        invokeAdviceMethod(getJoinPointMatch(), null, null);    }}

AspectJAfterAdviceinvoke()办法中,将后置告诉逻辑的调用放在了finally中,所以后置告诉的逻辑肯定会等到其它告诉和指标办法执行后再执行。

那么到这里,办法调用器ReflectiveMethodInvocation调用拦截器和指标办法的流程曾经造成了一个闭环,借助递归调用的个性,指标办法和拦截器都会被调用到,尽管指标办法的调用会在所有拦截器调用之后,然而指标办法的执行是会先于某些告诉的执行的(比方后置告诉)。

最初还须要阐明,在ReflectiveMethodInvocationproceed()办法中,应用了currentInterceptorIndex字段来标识以后调用到了第几个拦截器,初始值为-1,每次应用前先加1(即++currentInterceptorIndex),那么拦截器在汇合中的地位理论是会影响拦截器的invoke()办法的调用程序,那么通过下面的源码剖析,这个调用程序的影响能够归纳如下。

  • 不同告诉对应的拦截器在汇合中的地位不会影响不同告诉的调用程序,比方前置告诉逻辑的执行必定会先于后置告诉逻辑的执行;
  • 雷同告诉对应的拦截器在汇合中的地位会影响雷同告诉的调用程序,比方前置告诉1在汇合中的索引比前置告诉2在汇合中的索引小,那么前置告诉1的逻辑的执行会先于前置告诉2。

三. 时序图

AOP动静代理对象执行办法时,调用时序图如下所示。

总结

SpringAOP的动静代理对象持有告诉链和指标对象,那么在调用动静代理对象办法时,会先从告诉链中找出可能作用于指标办法的Advisor,而后将每个符合条件的Advisor封装成MethodInvocation并退出汇合,称MethodInvocation的汇合为拦截器链,失去拦截器链后,会基于拦截器链创立办法调用器MethodInvocation,而后通过MethodInvocationproceed()办法调用拦截器和指标办法的逻辑。