1. 程式人生 > >Spring Aop之Cglib實現原理詳解

Spring Aop之Cglib實現原理詳解

Spring Aop實現對目標物件的代理,AOP的兩種實現方式:Jdk代理和Cglib代理。這兩種代理的區別在於,Jdk代理與目標類都會實現同一個介面,並且在代理類中會呼叫目標類中被代理的方法,呼叫者實際呼叫的則是代理類的方法,通過這種方式我們就可以在代理類中織入切面邏輯;Jdk代理存在的問題在於目標類被代理的方法必須實現某個介面,Cglib代理則是為了解決這個問題而存在的,其實現代理的方式是通過為目標類動態生成一個子類,通過在子類中織入相應邏輯來達到織入代理邏輯的目的。

關於Jdk代理和Cglib代理,其優缺點主要在於:

  • Jdk代理生成的代理類只有一個,因而其編譯速度是非常快的;而由於被代理的目標類是動態傳入代理類中的,Jdk代理的執行效率相對來說低一點,這也是Jdk代理被稱為動態代理的原因;
  • Cglib代理需要為每個目標類生成相應的子類,因而在實際執行過程中,其可能會生成非常多的子類,過多的子類始終不是太好的,因為這影響了虛擬機器編譯類的效率;但由於在呼叫過程中,代理類的方法是已經靜態編譯生成了的,因而Cglib代理的執行效率相對來說高一些。

本文主要講解Spring Aop是如何通過Cglib代理實現將切面邏輯織入目標類的。

1. AopProxy織入物件生成

前面我們講過,Spring Aop織入切面邏輯的入口方法是AbstractAutoProxyCreator.createProxy()方法,如下是該方法的原始碼:


protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
        @Nullable Object[] specificInterceptors, TargetSource targetSource) {
    
    // 如果當前beanFactory實現了ConfigurableListableBeanFactory介面,則將需要被代理的
    // 物件暴露出來
    if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
        AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) 
            this.beanFactory, beanName, beanClass);
    }

    // 建立代理工廠
    ProxyFactory proxyFactory = new ProxyFactory();
    // 複製proxyTargetClass,exposeProxy等屬性
    proxyFactory.copyFrom(this);

    // 如果當前設定了不使用Cglib代理目標類,則判斷目標類是否設定了preserveTargetClass屬性,
    // 如果設定了,則還是強制使用Cglib代理目標類;如果沒有設定,則判斷目標類是否實現了相關介面,
    // 沒有設定,則還是使用Cglib代理。需要注意的是Spring預設使用的是Jdk代理來織入切面邏輯。
    if (!proxyFactory.isProxyTargetClass()) {
        // 判斷目標類是否設定了preserveTargetClass屬性
        if (shouldProxyTargetClass(beanClass, beanName)) {
            proxyFactory.setProxyTargetClass(true);
        } else {
            // 判斷目標類是否實現了相關介面
            evaluateProxyInterfaces(beanClass, proxyFactory);
        }
    }

    // 將需要織入的切面邏輯都轉換為Advisor物件
    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    proxyFactory.addAdvisors(advisors);
    proxyFactory.setTargetSource(targetSource);
    // 提供的hook方法,供子類實現以實現對代理工廠的定製
    customizeProxyFactory(proxyFactory);

    proxyFactory.setFrozen(this.freezeProxy);
    // 當前判斷邏輯預設返回false,子類可進行重寫,對於AnnotationAwareAspectJAutoProxyCreator,
    // 其重寫了該方法返回true,因為其已經對獲取到的Advisor進行了過濾,後面不需要在對目標類進行重新
    // 匹配了
    if (advisorsPreFiltered()) {
        proxyFactory.setPreFiltered(true);
    }

    // 生成代理類
    return proxyFactory.getProxy(getProxyClassLoader());
}

可以看到,在生成代理類之前,主要做了兩件事:①判斷使用Jdk代理還是Cglib代理;②設定相關的屬性。這裡我們繼續看最後的ProxyFactory.getProxy()方法:


public Object getProxy(@Nullable ClassLoader classLoader) {
    // 首先獲取AopProxy物件,其主要有兩個實現:JdkDynamicAopProxy和ObjenesisCglibAopProxy,
    // 分別用於Jdk和Cglib代理類的生成,其getProxy()方法則用於獲取具體的代理物件
    return createAopProxy().getProxy(classLoader);
}

上面的createAopProxy()方法可以理解為一個工廠方法,返回值是一個AopProxy型別的物件,其內部根據具體的條件生成相應的子類物件,即JdkDynamicAopProxy和ObjenesisCglibAopProxy。後面則通過呼叫AopProxy.getProxy()方法獲取代理過的物件。如下是createAopProxy()方法的實現邏輯:


public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    // 判斷當前類是否需要進行執行時優化,或者是指定了使用Cglib代理的方式,再或者是目標類沒有使用者提供的
    // 相關介面,則使用Cglib代理實現代理邏輯的織入
    if (config.isOptimize() || config.isProxyTargetClass() || 
        hasNoUserSuppliedProxyInterfaces(config)) {
        Class<?> targetClass = config.getTargetClass();
        if (targetClass == null) {
            throw new AopConfigException("TargetSource cannot determine target class: " 
                + "Either an interface or a target is required for proxy creation.");
        }
        // 如果被代理的類是一個介面,或者被代理的類是使用Jdk代理生成的類,此時還是使用Jdk代理
        if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
        }
        
        // 返回Cglib代理織入類物件
        return new ObjenesisCglibAopProxy(config);
    } else {
        // 返回Jdk代理織入類物件
        return new JdkDynamicAopProxy(config);
    }
}

這裡可以看到,本文需要講解的Cglib代理邏輯的織入就在ObjenesisCglibAopProxy.getProxy()方法中。

2. 代理邏輯的織入

關於代理邏輯的織入,其實現主體還是通過Enhancer來實現,即通過需要織入的Advisor列表,生成Callback物件,並將其設定到Enhancer物件中,最後通過Enhancer生成目標物件。如下是AopProxy.getProxy()方法的原始碼:


public Object getProxy(@Nullable ClassLoader classLoader) {
    if (logger.isDebugEnabled()) {
        logger.debug("Creating CGLIB proxy: target source is " 
            + this.advised.getTargetSource());
    }

    try {
        Class<?> rootClass = this.advised.getTargetClass();
        Assert.state(rootClass != null, 
                     "Target class must be available for creating a CGLIB proxy");

        // 判斷當前類是否是已經通過Cglib代理生成的類,如果是的,則獲取其原始父類,
        // 並將其介面設定到需要代理的介面中
        Class<?> proxySuperClass = rootClass;
        if (ClassUtils.isCglibProxyClass(rootClass)) {
            // 獲取父類
            proxySuperClass = rootClass.getSuperclass();
            // 獲取父類實現的介面,並將其設定到需要代理的介面中
            Class<?>[] additionalInterfaces = rootClass.getInterfaces();
            for (Class<?> additionalInterface : additionalInterfaces) {
                this.advised.addInterface(additionalInterface);
            }
        }

        // 對目標類進行檢查,主要檢查點有三個:
        // 1. 目標方法不能使用final修飾;
        // 2. 目標方法不能是private型別的;
        // 3. 目標方法不能是包訪問許可權的;
        // 這三個點滿足任何一個,當前方法就不能被代理,此時該方法就會被略過
        validateClassIfNecessary(proxySuperClass, classLoader);

        // 建立Enhancer物件,並且設定ClassLoader
        Enhancer enhancer = createEnhancer();
        if (classLoader != null) {
            enhancer.setClassLoader(classLoader);
            if (classLoader instanceof SmartClassLoader &&
                ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
                enhancer.setUseCache(false);
            }
        }
        enhancer.setSuperclass(proxySuperClass);
        // 這裡AopProxyUtils.completeProxiedInterfaces()方法的主要目的是為要生成的代理類
        // 增加SpringProxy,Advised,DecoratingProxy三個需要實現的介面。這裡三個介面的作用如下:
        // 1. SpringProxy:是一個空介面,用於標記當前生成的代理類是Spring生成的代理類;
        // 2. Advised:Spring生成代理類所使用的屬性都儲存在該介面中,
        //    包括Advisor,Advice和其他相關屬性;
        // 3. DecoratingProxy:該介面用於獲取當前代理物件所代理的目標物件的Class型別。
        enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
        enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
        enhancer.setStrategy(new 
            ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));

        // 獲取當前需要織入到代理類中的邏輯
        Callback[] callbacks = getCallbacks(rootClass);
        Class<?>[] types = new Class<?>[callbacks.length];
        for (int x = 0; x < types.length; x++) {
            types[x] = callbacks[x].getClass();
        }

        // 設定代理類中各個方法將要使用的切面邏輯,這裡ProxyCallbackFilter.accept()方法返回
        // 的整型值正好一一對應上面Callback陣列中各個切面邏輯的下標,也就是說這裡的CallbackFilter
        // 的作用正好指定了代理類中各個方法將要使用Callback陣列中的哪個或哪幾個切面邏輯
        enhancer.setCallbackFilter(new ProxyCallbackFilter(
            this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, 
            this.fixedInterceptorOffset));
        enhancer.setCallbackTypes(types);

        // 生成代理物件
        return createProxyClassAndInstance(enhancer, callbacks);
    } catch (CodeGenerationException | IllegalArgumentException ex) {
        throw new AopConfigException("Could not generate CGLIB subclass of class [" 
            + this.advised.getTargetClass() + "]: Common causes of this problem "  
            + "include using a final class or a non-visible class", ex);
    } catch (Throwable ex) {
        throw new AopConfigException("Unexpected AOP exception", ex);
    }
}

可以看到,這裡的AopProxy.getProxy()方法就是生成代理物件的主幹邏輯。上面的邏輯中主要有兩個部分需要重點講解:①如果獲取Callback陣列;②CallbackFilter的作用。關於第一點,我們後面會進行重點講解,至於第二點,這裡我們需要理解的就是CallbackFilter.accept()方法接收一個Method型別的引數,該引數也即當前要生成的代理邏輯的方法,這裡的accept()方法將返回目標當前要織入代理邏輯的方法所需要使用的切面邏輯,也即Callback物件在Callback陣列中的下標。關於CallbackFilter的使用原理,讀者可以閱讀實戰CGLib系列之proxy篇(二):回撥過濾CallbackFilter這篇文章。下面我們繼續閱讀getCallbacks()的原始碼:


private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
    boolean exposeProxy = this.advised.isExposeProxy();
    boolean isFrozen = this.advised.isFrozen();
    boolean isStatic = this.advised.getTargetSource().isStatic();

    // 使用者自定義的代理邏輯的主要織入類
    Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);

    Callback targetInterceptor;
    // 判斷如果要暴露代理物件,如果是,則使用AopContext設定將代理物件設定到ThreadLocal中
    // 使用者則可以通過AopContext獲取目標物件
    if (exposeProxy) {
        // 判斷被代理的物件是否是靜態的,如果是靜態的,則將目標物件快取起來,每次都使用該物件即可,
        // 如果目標物件是動態的,則在DynamicUnadvisedExposedInterceptor中每次都生成一個新的
        // 目標物件,以織入後面的代理邏輯
        targetInterceptor = isStatic ?
          new StaticUnadvisedExposedInterceptor(
            this.advised.getTargetSource().getTarget()) :
          new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource());
    } else {
        // 下面兩個類與上面兩個的唯一區別就在於是否使用AopContext暴露生成的代理物件
        targetInterceptor = isStatic ?
            new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
        new DynamicUnadvisedInterceptor(this.advised.getTargetSource());
    }

    // 當前Callback用於一般的不用背代理的方法,這些方法
    Callback targetDispatcher = isStatic ?
        new StaticDispatcher(this.advised.getTargetSource().getTarget()) 
        : new SerializableNoOp();

    // 將獲取到的callback組裝為一個數組
    Callback[] mainCallbacks = new Callback[] {
        aopInterceptor,  // 使用者自己定義的攔截器
        targetInterceptor,  // 根據條件是否暴露代理物件的攔截器
        new SerializableNoOp(),  // 不做任何操作的攔截器
        targetDispatcher, this.advisedDispatcher,  // 用於儲存Advised物件的分發器
        new EqualsInterceptor(this.advised),  // 針對equals方法呼叫的攔截器
        new HashCodeInterceptor(this.advised)  // 針對hashcode方法呼叫的攔截器
    };

    Callback[] callbacks;
    // 如果目標物件是靜態的,也即可以快取的,並且切面邏輯的呼叫鏈是固定的,
    // 則對目標物件和整個呼叫鏈進行快取
    if (isStatic && isFrozen) {
        Method[] methods = rootClass.getMethods();
        Callback[] fixedCallbacks = new Callback[methods.length];
        this.fixedInterceptorMap = new HashMap<>(methods.length);

        for (int x = 0; x < methods.length; x++) {
            // 獲取目標物件的切面邏輯
            List<Object> chain = 
                this.advised.getInterceptorsAndDynamicInterceptionAdvice(
                methods[x], rootClass);
            fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
                chain, this.advised.getTargetSource().getTarget(), 
                this.advised.getTargetClass());
            // 對呼叫鏈進行快取
            this.fixedInterceptorMap.put(methods[x].toString(), x);
        }

        // 將生成的靜態呼叫鏈存入Callback陣列中
        callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
        System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
        System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, 
            fixedCallbacks.length);
        // 這裡fixedInterceptorOffset記錄了當前靜態的呼叫鏈的切面邏輯的起始位置,
        // 這裡記錄的用處在於後面使用CallbackFilter的時候,如果發現是靜態的呼叫鏈,
        // 則直接通過該引數獲取相應的呼叫鏈,而直接略過了前面的動態呼叫鏈
        this.fixedInterceptorOffset = mainCallbacks.length;
    } else {
        callbacks = mainCallbacks;
    }
    return callbacks;
}

這裡的getCallbacks()方法主要做了三件事:①獲取目標物件的動態呼叫鏈;②判斷是否設定了exposeProxy屬性,如果設定了,則生成一個可以暴露代理物件的Callback物件,否則生成一個不做任何處理直接呼叫目標物件的Callback物件;③判斷目標物件是否是靜態的,並且當前的切面邏輯是否是固定的,如果是,則將目標物件和呼叫鏈進行快取,以便後續直接呼叫。這裡需要說明的一個點在於第三點,因為在判斷目標物件為靜態物件,並且呼叫鏈是固定的時候,會將目標物件和呼叫鏈進行快取,並且封裝到指定的Callback物件中。這裡讀者可能會疑問為什麼動態呼叫鏈和靜態呼叫鏈都進行了快取,這和前面講解的CallbackFilter是息息相關的,因為上述程式碼最後使用fixedInterceptorOffset記錄了當前靜態呼叫鏈在陣列中儲存的位置,我們前面也講了,Enhancer可以通過CallbackFilter返回的整數值來動態的指定從當前物件Callback陣列中的第幾個環繞邏輯開始織入,這裡就會使用到fixedInterceptorOffset。從上述程式碼中可以看出,使用者自定義的呼叫鏈是在DynamicAdvisedInterceptor中生成的(關於靜態呼叫鏈的生成實際上是同樣的邏輯,只不過靜態呼叫鏈會被快取),這裡我們看看DynamicAdvisedInterceptor的實現原始碼:


public Object intercept(Object proxy, Method method, Object[] args, 
        MethodProxy methodProxy) throws Throwable {
    Object oldProxy = null;
    boolean setProxyContext = false;
    Object target = null;
    // 通過TargetSource獲取目標物件
    TargetSource targetSource = this.advised.getTargetSource();
    try {
        // 判斷如果需要暴露代理物件,則將當前代理物件設定到ThreadLocal中
        if (this.advised.exposeProxy) {
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }

        target = targetSource.getTarget();
        Class<?> targetClass = (target != null ? target.getClass() : null);
        // 獲取目標物件切面邏輯的環繞鏈
        List<Object> chain = this.advised
            .getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
        Object retVal;
        if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
            // 對引數進行處理,以使其與目標方法的引數型別一致,尤其對於陣列型別,
            // 會單獨處理其資料型別與實際型別一致
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            // 因為沒有切面邏輯需要織入,這裡直接呼叫目標方法
            retVal = methodProxy.invoke(target, argsToUse);
        } else {
            // 通過生成的呼叫鏈,對目標方法進行環繞呼叫
            retVal = new CglibMethodInvocation(proxy, target, method, 
                args, targetClass, chain, methodProxy).proceed();
        }
        
        // 對返回值進行處理,如果返回值就是當前目標物件,那麼將代理生成的代理物件返回;
        // 如果返回值為空,並且返回值型別是非void的基本資料型別,則丟擲異常;
        // 如果上述兩個條件都不符合,則直接將生成的返回值返回
        retVal = processReturnType(proxy, target, method, retVal);
        return retVal;
    } finally {
        // 如果目標物件不是靜態的,則呼叫TargetSource.releaseTarget()方法釋放目標物件
        if (target != null && !targetSource.isStatic()) {
            targetSource.releaseTarget(target);
        }
        
        // 將代理物件設定為前面(外層邏輯)呼叫設定的物件,以防止暴露出來的代理物件不一致
        if (setProxyContext) {
            AopContext.setCurrentProxy(oldProxy);
        }
    }
}

這裡intercept()方法裡主要邏輯有兩點:①為目標物件生成切面邏輯呼叫鏈;②通過切面邏輯對目標物件進行環繞,並且進行呼叫。關於這兩點,我們都會進行講解,這裡我們首先看看Cglib是如何生成呼叫鏈的,如下是getInterceptorsAndDynamicInterceptionAdvice()方法最終呼叫的原始碼,中間略過了部分比較簡單的呼叫:


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

    List<Object> interceptorList = new ArrayList<>(config.getAdvisors().length);
    Class<?> actualClass = (targetClass != null ? 
        targetClass : method.getDeclaringClass());
    // 判斷切面邏輯中是否有IntroductionAdvisor型別的Advisor
    boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
    AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();

    for (Advisor advisor : config.getAdvisors()) {
        if (advisor instanceof PointcutAdvisor) {
            PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
            // 這裡判斷切面邏輯的呼叫鏈是否提前進行過過濾,如果進行過,則不再進行目標方法的匹配,
            // 如果沒有,則再進行一次匹配。這裡我們使用的AnnotationAwareAspectJAutoProxyCreator
            // 在生成切面邏輯的時候就已經進行了過濾,因而這裡返回的是true,本文最開始也對這裡進行了講解
            if (config.isPreFiltered() || pointcutAdvisor.getPointcut()
                .getClassFilter().matches(actualClass)) {
                // 將Advisor物件轉換為MethodInterceptor陣列
                MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                // 這裡進行匹配的時候,首先會檢查是否為IntroductionAwareMethodMatcher型別的
                // Matcher,如果是,則呼叫其定義的matches()方法進行匹配,如果不是,則直接呼叫
                // 當前切面的matches()方法進行匹配。這裡由於前面進行匹配時可能存在部分在靜態匹配時
                // 無法確認的方法匹配結果,因而這裡呼叫是必要的,而對於能夠確認的匹配邏輯,這裡呼叫
                // 也是非常迅速的,因為前面已經對匹配結果進行了快取
                if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
                    // 判斷如果是動態匹配,則使用InterceptorAndDynamicMethodMatcher對其進行封裝
                    if (mm.isRuntime()) {
                        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;
            // 判斷如果為IntroductionAdvisor型別的Advisor,則將呼叫鏈封裝為Interceptor陣列
            if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
                Interceptor[] interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        } else {
            // 這裡是提供的使用自定義的轉換器對Advisor進行轉換的邏輯,因為getInterceptors()方法中
            // 會使用相應的Adapter對目標Advisor進行匹配,如果能匹配上,通過其getInterceptor()方法
            // 將自定義的Advice轉換為MethodInterceptor物件
            Interceptor[] interceptors = registry.getInterceptors(advisor);
            interceptorList.addAll(Arrays.asList(interceptors));
        }
    }

    return interceptorList;
}

這裡獲取呼叫鏈的邏輯其實比較簡單,其最終的目的就是將Advisor陣列一個一個的封裝為Interceptor物件。在進行Advisor封裝的時候,這裡分為了三種類型:

  • 如果目標切面邏輯是一般的切面邏輯,即PointcutAdvisor,則會在執行時對目標方法進行動態匹配,因為前面可能存在還不能確認的是否應該應用切面邏輯的方法;
  • 如果切面邏輯是IntroductionAdvisor的,則將其封裝為Interceptor型別的陣列;
  • 如果以上兩個都不是,說明切面邏輯可能是使用者自定義的切面邏輯,這裡就通過註冊的AdvisorAdapter進行匹配,如果某個Adapter能夠支援當前Advisor的轉換,則呼叫其getInterceptor()方法將Advisor轉換為MethodInterceptor返回。

下面我們看看Cglib是如何通過生成的切面呼叫鏈將目標物件進行環繞的。前面我們講了,將切面邏輯進行織入的邏輯在CglibMethodInvocation中,實際上其呼叫邏輯在其proceed()方法中,這裡我們直接看該方法的原始碼:


public Object proceed() throws Throwable {
    // 這裡currentInterceptorIndex記錄了當前呼叫鏈中正在呼叫的Intercepor的下標,該數值初始為-1
    if (this.currentInterceptorIndex == 
        this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        // 如果呼叫鏈為空,則直接呼叫目標方法
        return invokeJoinpoint();
    }

    // 獲取下一個需要織入的Interceptor邏輯
    Object interceptorOrInterceptionAdvice =
        this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
        InterceptorAndDynamicMethodMatcher dm =
            (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
        // 對動態的方法進行匹配,如果匹配成功,才進行呼叫,否則直接進行下一個Interceptor的呼叫
        if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
            return dm.interceptor.invoke(this);
        } else {
            return proceed();
        }
    } else {
        // 如果不需要進行動態匹配,則直接進行下一步的呼叫
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
}

這裡proceed()方法的邏輯比較簡單,其使用一個索引記錄了當前正在呼叫的Interceptor在呼叫鏈中的位置,並且依次對呼叫鏈進行呼叫,從而實現將切面邏輯織入目標物件的目的。這裡最終對目標物件的呼叫的邏輯在invokeJoinpoint()方法中。

3. 小結

本文首先講解Spring是如何通過配置的引數來選擇使用哪種代理方式的,然後重點講解了Spring Aop是如何使用Cglib代理實現代理邏輯的織入的。

原文連結:https://my.oschina.net/zhangxufeng/blog/1933830