天天看點

Spring系列之AOP分析之對目标對象的攔截過程(八)

我們在上一篇文章中簡單的說了調用動态代理對象方法的過程,也說了AOP攔截器執行鍊的生成過程。我們接着說AOP對目标對象的攔截過程。下面的代碼是我們要分析的重點:

//proxy:生成的動态代理對象
//target:目标對象
//method:目标方法
//args:目标方法參數
//targetClass:目标類對象
//chain: AOP攔截器執行鍊  是一個MethodInterceptor的集合 這個鍊條的擷取過程參考我們上一篇文章的内容
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
//開始執行AOP的攔截過程
retVal = invocation.proceed();

//構造ReflectiveMethodInvocation對象
protected ReflectiveMethodInvocation(
            Object proxy, Object target, Method method, Object[] arguments,
            Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {

        this.proxy = proxy;
        this.target = target;
        this.targetClass = targetClass;
        //橋接方法
        this.method = BridgeMethodResolver.findBridgedMethod(method);
        //轉換參數
        this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);
        this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
    }           
public Object proceed() throws Throwable {
        //    currentInterceptorIndex初始值為 -1 
        // 如果執行到鍊條的末尾 則直接調用連接配接點方法 即 直接調用目标方法
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            //下面會分析
            return invokeJoinpoint();
        }
        //擷取集合中的 MethodInterceptor
        Object interceptorOrInterceptionAdvice =
                this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        //如果是InterceptorAndDynamicMethodMatcher類型
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            InterceptorAndDynamicMethodMatcher dm =
                    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
            //這裡每一次都去比對是否适用于這個目标方法
            if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
                //如果比對則直接調用 MethodInterceptor的invoke方法
                //注意這裡傳入的參數是this 我們下面看一下 ReflectiveMethodInvocation的類型
                return dm.interceptor.invoke(this);
            }
            else {
                //如果不适用于此目标方法  則繼續執行下一個鍊條 
                //遞歸調用
                return proceed();
            }
        }
        else {
            //說明是适用于此目标方法的 直接調用 MethodInterceptor的invoke方法  傳入this即ReflectiveMethodInvocation執行個體
            //傳入this進入 這樣就可以形成一個調用的鍊條了
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }           

invokeJoinpoint方法

protected Object invokeJoinpoint() throws Throwable {
        //this.target 目标對象
        //this.method 目标方法
        this.arguments 目标方法參數資訊
        return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
    }
    public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)
            throws Throwable {

        // Use reflection to invoke the method.
        try {
            //設定方法可見性
            ReflectionUtils.makeAccessible(method);
            //反射調用  最終是通過反射去調用目标方法
            return method.invoke(target, args);
        }
        catch (InvocationTargetException ex) {
            // Invoked method threw a checked exception.
            // We must rethrow it. The client won't see the interceptor.
            throw ex.getTargetException();
        }
        catch (IllegalArgumentException ex) {
            throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +
                    method + "] on target [" + target + "]", ex);
        }
        catch (IllegalAccessException ex) {
            throw new AopInvocationException("Could not access method [" + method + "]", ex);
        }
    }           

ReflectiveMethodInvocation的UML類圖如下:

MethodInterceptorChain

OK,我們在proceed()這個方法中看到了AOP對于目标方法的一個攔截的過程,其中很重要的一個點是調用MethodInterceptor的invoke方法。我們先看一下MethodInterceptor的主要UML類圖(由于我們在開發中使用AspectJ注解的方式越來越多,是以我們這裡說的基本上都是基于AspectJ注解的):

從上圖我們也可以看到不同的通知其實相當于不同的MethodInterceptor類型。像前置通知會交給:MethodBeforeAdviceInterceptor來進行處理,後置通知是由AspectJAfterAdvice來處理的,環繞通知是由AspectJAroundAdvice來處理的。我們也挑幾個通知類型來說一下具體的調用過程。先說一下前置通知:

MethodBeforeAdviceInterceptor

//實作了MethodInterceptor接口
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
    //這個對象的擷取參考這個方法org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvice
    //在之前的文章中有說過 不再描述
    //這個MethodBeforeAdvice是AspectJMethodBeforeAdvice執行個體
    private MethodBeforeAdvice advice;
    
    public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
        Assert.notNull(advice, "Advice must not be null");
        this.advice = advice;
    }
    
    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        //這裡就會執行  前置通知的邏輯 這裡的advice是 AspectJMethodBeforeAdvice
        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
        //這裡傳入的MethodInvocation是ReflectiveMethodInvocation對象,即前面說的  傳入this
        //相當于ReflectiveMethodInvocation.proceed() 遞歸調用。
        return mi.proceed();
    }
}           

AspectJMethodBeforeAdvice#before代碼如下:

@Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        //這裡傳進來的目标對象、目标參數、目标方法都沒有用到
        invokeAdviceMethod(getJoinPointMatch(), null, null);
    }
    protected JoinPointMatch getJoinPointMatch() {
        //這裡從線程上下文中擷取MethodInvocation 看到這裡你也許會感到奇怪  跟着文章分析來看 我們沒有在設定過上下文的值啊
        //這裡是怎麼擷取到MethodInvocation 的對象的呢?
        //不知道你是否還記得 我們在擷取Advisor的時候 調用過這樣的一個方法org.springframework.aop.aspectj.AspectJProxyUtils#makeAdvisorChainAspectJCapableIfNecessary
        //在這個方法中會有這樣的一段代碼 
        // if (foundAspectJAdvice && //!advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
        //     如果擷取到了 Advisor  則向 Advisor集合中添加第一個元素 即 ExposeInvocationInterceptor.ADVISOR
        //也就是說 我們的 Advisor清單中的第一個元素為ExposeInvocationInterceptor.ADVISOR 它是一個DefaultPointcutAdvisor的執行個體
        // 對于任何的目标方法都傳回true  它的Advice是ExposeInvocationInterceptor
        //        advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
        //        return true;
        //    }
        // 這樣我們就不難了解了,在調用ReflectiveMethodInvocation#proceed的時候第一個調用的MethodInterceptor是ExposeInvocationInterceptor
        //ExposeInvocationInterceptor的invoke方法的内容如下:
        //    public Object invoke(MethodInvocation mi) throws Throwable {
        //   先取出舊的MethodInvocation的值
        //    MethodInvocation oldInvocation = invocation.get();
        //    這裡設定新的 MethodInvocation 就是這裡了!!!
        //    invocation.set(mi);
        //    try {
        //      遞歸調用
        //        return mi.proceed();
        ///   }
        //   finally {
        //       invocation.set(oldInvocation);
        //   }
    //      }
        MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
        if (!(mi instanceof ProxyMethodInvocation)) {
            throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
        }
        //這裡主要是擷取 JoinPointMatch
        return getJoinPointMatch((ProxyMethodInvocation) mi);
    }           

關于invokeAdviceMethod方法的内容我們在下一篇文章中繼續分析