转载

Spring源码解析 -- AOP原理(2)

源码分析基于spring 4.3.x

本文承接上一篇文章对Spring AOP的分析,继续分析spring如何对AOP中多个通知进行链式调用的。

关于阅读源码的思路,可参考 -- 如何阅读java源码

《Spring源码解析 -- AOP原理(1)》 中说了,JdkDynamicAopProxy实现了InvocationHandler,正是这个类调用​AOP通知中定义的增强方法。

JdkDynamicAopProxy#invoke

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

        TargetSource targetSource = this.advised.targetSource;
        Class<?> targetClass = null;
        Object target = null;

        try {
            ... // #1

            Object retVal;

            if (this.advised.exposeProxy) {
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }

            target = targetSource.getTarget();
            if (target != null) {
                targetClass = target.getClass();
            }

            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);    // #2

            if (chain.isEmpty()) {
                Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);    // #3
            }
            else {
                invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);    // #4
                retVal = invocation.proceed();    // #5
            }

            Class<?> returnType = method.getReturnType();
            if (retVal != null && retVal == target &&
                    returnType != Object.class && returnType.isInstance(proxy) &&
                    !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {    // #6
                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);
            }
        }
    }

#1 处理equals/hashCode等方法,直接调用目标方法

#2 getInterceptorsAndDynamicInterceptionAdvice -- 获取方法拦截器

#3 没有方法拦截器,直接调用目标方法

#4 构造调用链ReflectiveMethodInvocation

#5 调用调用链

#6 处理特殊场景 -- 方法返回值为this

AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice -> DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
        Advised config, Method method, Class<?> targetClass) {

    // This is somewhat tricky... We have to process introductions first,
    // but we need to preserve order in the ultimate list.
    List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
    Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
    boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
    AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();

    for (Advisor advisor : config.getAdvisors()) {
        if (advisor instanceof PointcutAdvisor) {    
            // Add it conditionally.
            PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
            if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {    // #1
                MethodInterceptor[] interceptors = registry.getInterceptors(advisor);    // #2    
                MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();    
                if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {    // #3
                    if (mm.isRuntime()) {    // #4
                        // Creating a new object instance in the getInterceptors() method
                        // isn't a problem as we normally cache created chains.
                        for (MethodInterceptor interceptor : interceptors) {
                            interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));    // #5
                        }
                    }
                    else {
                        interceptorList.addAll(Arrays.asList(interceptors));    // #6
                    }
                }
            }
        }
        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;
}

#1 判断class是否匹配pointcut

#2 getInterceptors -- 将advisor转化为MethodInterceptor方法拦截器,MethodInterceptor#invoke负责调用被拦截的方法

#3 判断method是否匹配pointcut

#4 是否运行时判断

#5 添加InterceptorAndDynamicMethodMatcher到结果

#6 添加MethodInterceptor到结果

DefaultAdvisorAdapterRegistry#getInterceptors:

public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
        List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);
        Advice advice = advisor.getAdvice();
        if (advice instanceof MethodInterceptor) {
            interceptors.add((MethodInterceptor) advice);
        }
        for (AdvisorAdapter adapter : this.adapters) {
            if (adapter.supportsAdvice(advice)) {
                interceptors.add(adapter.getInterceptor(advisor));
            }
        }
        if (interceptors.isEmpty()) {
            throw new UnknownAdviceTypeException(advisor.getAdvice());
        }
        return interceptors.toArray(new MethodInterceptor[interceptors.size()]);
    }

有三个Advice没有实现MethodInterceptor,通过DefaultAdvisorAdapterRegistry#adapters适配

public DefaultAdvisorAdapterRegistry() {
        registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
        registerAdvisorAdapter(new AfterReturningAdviceAdapter());
        registerAdvisorAdapter(new ThrowsAdviceAdapter());
    }

回到JdkDynamicAopProxy#invoke方法 #5 步骤,调用调用链

ReflectiveMethodInvocation#proceed

public Object proceed() throws Throwable {
    //    We start with an index of -1 and increment early.
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {    // #1
        return invokeJoinpoint();    // #2
    }

    Object interceptorOrInterceptionAdvice =
            this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);    //#3
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {    //#4
        ...
    }
    else {
        // It's an interceptor, so we just invoke it: The pointcut will have
        // been evaluated statically before this object was constructed.
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);    //#5
    }
}

#1 判断是否到拦截器链末尾,注意currentInterceptorIndex初始值是-1

#2 拦截器已经调用完,调用被拦截的方法

#3 获取下一个拦截器

#4 是否为需要运行时判断

#5 直接调用拦截器

调用链ReflectiveMethodInvocation中的节点是拦截器MethodInterceptor。

ReflectiveMethodInvocation#proceed方法会获取下一个拦截器,并调用MethodInterceptor#invoke方法。

注意,调用拦截器MethodInterceptor#invoke方法时会将调用链ReflectiveMethodInvocation作为参数,拦截器MethodInterceptor#invoke执行完逻辑后,又调用ReflectiveMethodInvocation#proceed,继续调用下一个拦截器。

看看AspectJAroundAdvice的实现

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;    // #1
    ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);    // #2
    JoinPointMatch jpm = getJoinPointMatch(pmi);
    return invokeAdviceMethod(pjp, jpm, null, null);    // #3
}

#1 获取调用链

#2 使用调用链构造一个MethodInvocationProceedingJoinPoint

#3 调用增强方法

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

invokeAdviceMethodWithGivenArgs -- 通过反射调用增强方法,就是执行Around通知

argBinding -- 负责参数绑定

AbstractAspectJAdvice#argBinding

protected Object[] argBinding(JoinPoint jp, JoinPointMatch jpMatch, Object returnValue, Throwable ex) {
    calculateArgumentBindings();    //#1

    // AMC start
    Object[] adviceInvocationArgs = new Object[this.parameterTypes.length];
    int numBound = 0;

    if (this.joinPointArgumentIndex != -1) {    //#2
        adviceInvocationArgs[this.joinPointArgumentIndex] = jp;
        numBound++;
    }
    else if (this.joinPointStaticPartArgumentIndex != -1) {
        adviceInvocationArgs[this.joinPointStaticPartArgumentIndex] = jp.getStaticPart();
        numBound++;
    }

    if (!CollectionUtils.isEmpty(this.argumentBindings)) {    //#3
        // binding from pointcut match
        if (jpMatch != null) {
            PointcutParameter[] parameterBindings = jpMatch.getParameterBindings();
            for (PointcutParameter parameter : parameterBindings) {
                String name = parameter.getName();
                Integer index = this.argumentBindings.get(name);
                adviceInvocationArgs[index] = parameter.getBinding();
                numBound++;
            }
        }
        // binding from returning clause
        if (this.returningName != null) {
            Integer index = this.argumentBindings.get(this.returningName);
            adviceInvocationArgs[index] = returnValue;
            numBound++;
        }
        // binding from thrown exception
        if (this.throwingName != null) {
            Integer index = this.argumentBindings.get(this.throwingName);
            adviceInvocationArgs[index] = ex;
            numBound++;
        }
    }

    if (numBound != this.parameterTypes.length) {
        throw new IllegalStateException("Required to bind " + this.parameterTypes.length +
                " arguments, but only bound " + numBound + " (JoinPointMatch " +
                (jpMatch == null ? "was NOT" : "WAS") + " bound in invocation)");
    }

    return adviceInvocationArgs;
}

#1 通过反射获取参数名,返回名等信息,设置joinPointArgumentIndex,argumentBindings等属性

#2 添加JoinPointMatch到增强方法的参数中

#3 添加被拦截方法参数,返回值,异常等数据到增强方法的参数中

在环绕通知中,我们需要编写如下代码

@Around("...")
    public Object methodAroundLog(ProceedingJoinPoint joinPoint) throws Throwable {
        Object result = joinPoint.proceed(joinPoint.getArgs());
        return result;
    }

这里 joinPoint.proceed(joinPoint.getArgs()); 调用了下一个拦截器(MethodInvocationProceedingJoinPoint#proceed会调用ReflectiveMethodInvocation#proceed),这样才能继续调用拦截器调用链。

@Before通知会调用MethodBeforeAdviceInterceptor

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

#1 执行@Before增强

#2 继续拦截器调用链

@After通知会调用AspectJAfterThrowingAdvice

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

#1 先调用拦截器链

#2 执行@After增强

到这里,spring aop的源码解析就完成了。

这部分还是挺复杂的,需要耐心点看源码。

如果您觉得本文不错,欢迎关注我的微信公众号,您的关注是我坚持的动力!

Spring源码解析 -- AOP原理(2)

原文  https://segmentfault.com/a/1190000022543640
正文到此结束
Loading...