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類圖如下:
ReflectiveMethodInvocation
MethodInterceptorChain
MethodInterceptorChain
OK,我們在proceed()這個方法中看到了AOP對於目標方法的一個攔截的過程,其中很重要的一個點是調用MethodInterceptor的invoke方法。我們先看一下MethodInterceptor的主要UML類圖(由於我們在開發中使用AspectJ註解的方式越來越多,所以我們這裏說的基本上都是基於AspectJ註解的):
MethodInterceptor
從上圖我們也可以看到不同的通知其實相當於不同的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方法的內容我們在下一篇文章中繼續分析

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章