天天看點

Spring Aop之Cglib實作原理詳解

  Spring 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代理實作代理邏輯的織入的。

本文來自雲栖社群合作夥伴“開源中國”

本文作者:王練

原文連結