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

我們在上一篇文章中簡單的說了一下SpringAOP使用JDK動態代理生成目標對象的過程,我們在這一篇文章中說一下SpringAOP對生成的動態代理對象的方法的攔截過程(即SpringAOP攔截過程),這個分析的過程可能會比較長。
在上一篇文章中我們說的使用JDK創建動態代理對象是用的JdkDynamicAopProxy這個類,這個類同時實現了InvocationHandler這個接口,實現了它的invoke方法,熟悉JDK動態代理的同學都知道,當我們調用動態代理對象的方法的時候,會進入到生成代理對象時所傳入的InvocationHandler實現類的invoke方法中,在這裏也就是指JdkDynamicAopProxy的invoke方法,我們進入到這個invoke方法中看一下:

    @Override
    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 {
            //接口中沒有定義 equals方法(這個方法定義形式和Object中保持一致 ),並且調用的方法是equals方法(即Object中定義的equals方法) 
            if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
                //調用 JdkDynamicAopProxy 中寫的equals方法
                return equals(args[0]);
            }else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
                //和上面的分析一樣
                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) {
                // Make invocation available if necessary.
                //把之前創建的代理對象放到線程上下文中
                //oldProxy爲之前線程上下文中的對象
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }
            //從TargetSource中獲取目標對象
            target = targetSource.getTarget();
            if (target != null) {
                targetClass = target.getClass();
            }
            //從Advised中根據方法名和目標類獲取 AOP攔截器執行鏈 重點要分析的內容
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
            //如果這個執行鏈爲空的話
            if (chain.isEmpty()) {
                //直接進行方法調用
                Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
            }
            else {
                //如果AOP攔截器執行鏈不爲空  說明有AOP通知存在
                invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                //開始調用
                retVal = invocation.proceed();
            }
            //方法的返回值類型
            Class<?> returnType = method.getReturnType();
            if (retVal != null && retVal == target && returnType.isInstance(proxy) &&
                    !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
                //return this
                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 {
            //如果目標對象不爲空  且目標對象是可變的 如prototype類型
            //通常我們的目標對象都是單例的  即targetSource.isStatic爲true
            if (target != null && !targetSource.isStatic()) {
                //釋放目標對象
                targetSource.releaseTarget(target);
            }
            if (setProxyContext) {
                //線程上下文復位
                AopContext.setCurrentProxy(oldProxy);
            }
        }
    }

在上面的方法中大致了說明了一下整個代理對象方法調用的執行過程,像equals和hashcode方法的調用,Advised子類的調用。重點就是在連接點處執行不同的通知類型的調用,即獲取AOP攔截執行鏈的調用。下面我們要分析的就是這個過程:
this.advised.getInterceptorsAndDynamicInterceptionAdvice。
我們這裏的advised是一個AdvisedSupport類型的實例,它可能是ProxyFactory的實例也可能是AspectJProxyFactory實例。我們進入到getInterceptorsAndDynamicInterceptionAdvice這個方法中去看一下:

    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
        //創建一個method的緩存對象 在MethodCacheKey中實現了equals和hashcode方法同時還實現了compareTo方法
        MethodCacheKey cacheKey = new MethodCacheKey(method);
        List<Object> cached = this.methodCache.get(cacheKey);
        //先從緩存中獲取 如果緩存中獲取不到 則再調用方法獲取,獲取之後放入到緩存中
        if (cached == null) {
            //調用的是advisorChainFactory的getInterceptorsAndDynamicInterceptionAdvice方法
            cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
                    this, method, targetClass);
            this.methodCache.put(cacheKey, cached);
        }
        return cached;
    }

上面的方法的調用過程是先從緩存中獲取,緩存中獲取不到的話,再交給AdvisorChainFactory,通過調用AdvisorChainFactory中的getInterceptorsAndDynamicInterceptionAdvice方法來獲取攔截器執行鏈,放入到緩存中。AdvisorChainFactory在SpringAOP中只有一個默認的實現類:DefaultAdvisorChainFactory,所以我們去這個DefaultAdvisorChainFactory類中看一下這個方法的內容。

    //在這個方法中傳入了三個實例,一個是Advised的實例 一個是目標方法 一個是目標類可能爲null
    //想想我們在前面的文章中說過的,在Advised中都有什麼內容
    @Override
    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
            Advised config, Method method, Class<?> targetClass) {
        //創建一個初始大小爲 之前獲取到的 通知個數的 集合
        List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
        //如果目標類爲null的話,則從方法簽名中獲取目標類
        Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
        //判斷目標類是否存在引介增強 通常爲false
        boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
        //這裏用了一個單例模式 獲取DefaultAdvisorAdapterRegistry實例
        //在Spring中把每一個功能都分的很細,每個功能都會有相應的類去處理 符合單一職責原則的地方很多 這也是值得我們借鑑的一個地方
        //AdvisorAdapterRegistry這個類的主要作用是將Advice適配爲Advisor 將Advisor適配爲對應的MethodInterceptor 我們在下面說明
        AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
        //循環 目標方法匹配的 通知
        for (Advisor advisor : config.getAdvisors()) {
            //如果是PointcutAdvisor類型的實例  我們大多數的Advisor都是PointcutAdvisor類型的
            if (advisor instanceof PointcutAdvisor) {
                PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
                //如果提前進行過 切點的匹配了  或者當前的Advisor適用於目標類
                if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                    //將Advisor適配爲MethodInterceptor
                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                    MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                    //檢測Advisor是否適用於此目標方法
                    if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
                        //MethodMatcher中的切點分爲兩種 一個是靜態的 一種是動態的
                        //如果isRuntime返回true 則是動態的切入點 每次方法的調用都要去進行匹配
                        //而靜態切入點則回緩存之前的匹配結果值 
                        if (mm.isRuntime()) {
                            //動態切入點 則會創建一個InterceptorAndDynamicMethodMatcher對象
                            //這個對象包含MethodInterceptor和MethodMatcher 的實例
                            for (MethodInterceptor interceptor : interceptors) {
                                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)) {
                    //將Advisor轉換爲Interceptor
                    Interceptor[] interceptors = registry.getInterceptors(advisor);
                    interceptorList.addAll(Arrays.asList(interceptors));
                }
            }
            //以上兩種都不是
            else {
                //將Advisor轉換爲Interceptor
                Interceptor[] interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        }
        return interceptorList;
    }

在上面這個方法中主要乾了這幾件事:
1、循環目標方法的所有Advisor
2、判斷Advisor的類型
如果是PointcutAdvisor的類型,則判斷此Advisor是否適用於此目標方法
如果是IntroductionAdvisor引介增強類型,則判斷此Advisor是否適用於此目標方法
如果以上都不是,則直接轉換爲Interceptor類型。
在上面的三個步驟中都幹了這樣的一件事,將Advisor轉換爲Interceptor類型。這裏用到了一個很重要的一個類:DefaultAdvisorAdapterRegistry。從類名我們可以看出這是一個Advisor的適配器註冊類。它的源碼如下:

public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {
    //初始化了一個size爲3的集合 因爲下面就添加了三個AdvisorAdapter
    private final List<AdvisorAdapter> adapters = new ArrayList<AdvisorAdapter>(3);
    /**
     * Create a new DefaultAdvisorAdapterRegistry, registering well-known adapters.
     */
    public DefaultAdvisorAdapterRegistry() {
        //在SpringAOP中只默認提供了這三種通知類型的適配器
        //爲什麼沒有其他通知類型的呢?參考AbstractAspectJAdvice下面的幾個通知類型
        //前置通知適配器
        registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
        //後置返回通知適配器
        registerAdvisorAdapter(new AfterReturningAdviceAdapter());
        //後置異常通知適配器
        registerAdvisorAdapter(new ThrowsAdviceAdapter());
    }
    //這個方法的作用主要是將Advice轉換爲Advisor的
    @Override
    public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
        //如果傳入的實例是Advisor 則直接返回
        if (adviceObject instanceof Advisor) {
            return (Advisor) adviceObject;
        }
        //如果傳入的實例不是 Advice類型 則直接拋出異常
        if (!(adviceObject instanceof Advice)) {
            throw new UnknownAdviceTypeException(adviceObject);
        }
        Advice advice = (Advice) adviceObject;
        //如果這個Advice是MethodInterceptor類型的實例,則直接包裝爲DefaultPointcutAdvisor
        //DefaultPointcutAdvisor中的Pointcut爲Pointcut.TRUE matches始終返回true
        if (advice instanceof MethodInterceptor) {
            return new DefaultPointcutAdvisor(advice);
        }
        //如果不是Advisor的實例 也不是MethodInterceptor類型的實例
        //看看是不是 上面的那種通知類型適配器所支持的類型
        for (AdvisorAdapter adapter : this.adapters) {
            // Check that it is supported.
            if (adapter.supportsAdvice(advice)) {
                return new DefaultPointcutAdvisor(advice);
            }
        }
        throw new UnknownAdviceTypeException(advice);
    }
    //這個方法是將 Advisor轉換爲 MethodInterceptor
    @Override
    public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
        List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);
        //從Advisor中獲取 Advice
        Advice advice = advisor.getAdvice();
        if (advice instanceof MethodInterceptor) {
            interceptors.add((MethodInterceptor) advice);
        }
        for (AdvisorAdapter adapter : this.adapters) {
            if (adapter.supportsAdvice(advice)) {
                //轉換爲對應的 MethodInterceptor類型
                //AfterReturningAdviceInterceptor MethodBeforeAdviceInterceptor  ThrowsAdviceInterceptor
                interceptors.add(adapter.getInterceptor(advisor));
            }
        }
        if (interceptors.isEmpty()) {
            throw new UnknownAdviceTypeException(advisor.getAdvice());
        }
        return interceptors.toArray(new MethodInterceptor[interceptors.size()]);
    }
    //新增的 Advisor適配器
    @Override
    public void registerAdvisorAdapter(AdvisorAdapter adapter) {
        this.adapters.add(adapter);
    }
}

所以this.advised.getInterceptorsAndDynamicInterceptionAdvice這個方法獲取的是目標方法的AOP攔截器執行鏈。

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