spring 5.0.x源碼學習系列七: 后置處理器ConfigurationClassPostProcessor之BeanFactoryPostProcessor身份

前言

一、ConfigurationClassPostProcessor之BeanFactoryPostProcessor身份

  • 它的這個身份同樣起到了非常重要的作用: 為全配置類添加cglib代理,防止以@Bean的方式創(chuàng)建bean時出現(xiàn)重復調(diào)用相同邏輯的問題。 接下來我們按照如下demo一起探究它。

二、項目demo

2.1 項目全景圖

在這里插入圖片描述

2.1.1 AppConfig

在這里插入圖片描述

2.1.2 Bean1

在這里插入圖片描述

2.1.3 Bean2

在這里插入圖片描述

2.1.4 Entry
在這里插入圖片描述

2.2 運行結果

2.2.1 AppConfig類中無@Configuration注解的運行結果

在這里插入圖片描述

2.2.1 AppConfig類中有@Configuration注解的運行結果

在這里插入圖片描述

2.3 解釋運行結果

情形 運行結果 原因
AppConfig中無@Configuration注解 打印了兩次"creating bean1" 運行的沒有一點毛病, 按照正常邏輯, 執(zhí)行了兩次(spring創(chuàng)建Bean1的時候調(diào)用了一次, 創(chuàng)建Bean2的時候又調(diào)用了一次)創(chuàng)建bean的方法, 所以輸出兩次"creating bean1", 沒毛病
AppConfig中存在@Configuration注解 只打印了一次"creating bean1" 是因為spring在執(zhí)行BeanFactoryPostProcessor后置處理器時. 執(zhí)行到了ConfigurationClassPostProcessor的postProcessBeanFactory方法, 此方法對所有的全注解類進行了CGLIB代理, 對方法進行了增強, 但此時只是將產(chǎn)生的cglib的class添加到了當前全配置類對應的beanDefinition的beanClass屬性中(注意: 此時并沒有產(chǎn)生bean, 只是改變了beanClass屬性)

2.4 查看cglib代理類內(nèi)容

2.4.1 設置指定屬性, 將cglib代理類保存至指定地方

// 將整個工程中產(chǎn)生的cglib代理類全部存入g盤的cglib文件夾中
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "g://cglib");

2.4.2 運行項目并查看文件夾

在這里插入圖片描述

2.4.3 將整個com文件夾copy至idea中可以解析class文件的目錄下

  • 因spring源碼是用gradle編譯的, 我copy進的是out文件夾中, 若是普通的maven項目, 把它copy至target文件夾中即可

  • 生成的代理類文件夾結構如下:


    在這里插入圖片描述
  • 代理類源碼:

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by Fernflower decompiler)
    //
    
    package com.eugene.sumarry.csdn.invokeBeanFactoryPostProcessor3;
    
    import java.lang.reflect.Method;
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.cglib.core.ReflectUtils;
    import org.springframework.cglib.core.Signature;
    import org.springframework.cglib.proxy.Callback;
    import org.springframework.cglib.proxy.MethodInterceptor;
    import org.springframework.cglib.proxy.MethodProxy;
    import org.springframework.cglib.proxy.NoOp;
    import org.springframework.context.annotation.ConfigurationClassEnhancer.EnhancedConfiguration;
    
    /**
     * 它繼承了AppConfig, 所以斷定它就是AppConfig類的cglib代理類
     */
    public class AppConfig$$EnhancerBySpringCGLIB$$912e823e extends AppConfig implements EnhancedConfiguration {
        private boolean CGLIB$BOUND;
        public static Object CGLIB$FACTORY_DATA;
        private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
        private static final Callback[] CGLIB$STATIC_CALLBACKS;
        private MethodInterceptor CGLIB$CALLBACK_0;
        private MethodInterceptor CGLIB$CALLBACK_1;
        private NoOp CGLIB$CALLBACK_2;
        private static Object CGLIB$CALLBACK_FILTER;
        private static final Method CGLIB$bean1$0$Method;
        private static final MethodProxy CGLIB$bean1$0$Proxy;
        private static final Object[] CGLIB$emptyArgs;
        private static final Method CGLIB$bean2$1$Method;
        private static final MethodProxy CGLIB$bean2$1$Proxy;
        private static final Method CGLIB$setBeanFactory$6$Method;
        private static final MethodProxy CGLIB$setBeanFactory$6$Proxy;
        public BeanFactory $$beanFactory;
    
        static void CGLIB$STATICHOOK1() {
            CGLIB$THREAD_CALLBACKS = new ThreadLocal();
            CGLIB$emptyArgs = new Object[0];
            Class var0 = Class.forName("com.eugene.sumarry.csdn.invokeBeanFactoryPostProcessor3.AppConfig$$EnhancerBySpringCGLIB$$912e823e");
            Class var1;
            CGLIB$setBeanFactory$6$Method = ReflectUtils.findMethods(new String[]{"setBeanFactory", "(Lorg/springframework/beans/factory/BeanFactory;)V"}, (var1 = Class.forName("org.springframework.beans.factory.BeanFactoryAware")).getDeclaredMethods())[0];
            CGLIB$setBeanFactory$6$Proxy = MethodProxy.create(var1, var0, "(Lorg/springframework/beans/factory/BeanFactory;)V", "setBeanFactory", "CGLIB$setBeanFactory$6");
            Method[] var10000 = ReflectUtils.findMethods(new String[]{"bean1", "()Lcom/eugene/sumarry/csdn/invokeBeanFactoryPostProcessor3/Bean1;", "bean2", "()Lcom/eugene/sumarry/csdn/invokeBeanFactoryPostProcessor3/Bean2;"}, (var1 = Class.forName("com.eugene.sumarry.csdn.invokeBeanFactoryPostProcessor3.AppConfig")).getDeclaredMethods());
            CGLIB$bean1$0$Method = var10000[0];
            CGLIB$bean1$0$Proxy = MethodProxy.create(var1, var0, "()Lcom/eugene/sumarry/csdn/invokeBeanFactoryPostProcessor3/Bean1;", "bean1", "CGLIB$bean1$0");
            CGLIB$bean2$1$Method = var10000[1];
            CGLIB$bean2$1$Proxy = MethodProxy.create(var1, var0, "()Lcom/eugene/sumarry/csdn/invokeBeanFactoryPostProcessor3/Bean2;", "bean2", "CGLIB$bean2$1");
        }
    
        final Bean1 CGLIB$bean1$0() {
            return super.bean1();
        }
    
        /**
         * 代理增強的bean1方法
         */
        public final Bean1 bean1() {
            MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
            if (var10000 == null) {
                CGLIB$BIND_CALLBACKS(this);
                var10000 = this.CGLIB$CALLBACK_0;
            }
    
            return var10000 != null ? (Bean1)var10000.intercept(this, CGLIB$bean1$0$Method, CGLIB$emptyArgs, CGLIB$bean1$0$Proxy) : super.bean1();
        }
    
        final Bean2 CGLIB$bean2$1() {
            return super.bean2();
        }
    
        /**
         * 代理增強的bean2方法
         */
        public final Bean2 bean2() {
            // 這里獲取到產(chǎn)生cglib代理類時的方法攔截器
            // 在spring中默認的方法攔截器有這三個:
            // private static final Callback[] CALLBACKS = new Callback[] {
            //          new BeanMethodInterceptor(),
            //          new BeanFactoryAwareMethodInterceptor(),
            //          NoOp.INSTANCE
            //  };
            // 方法攔截器的具體作用沒有去研究, 這里大致走的是方法攔截器, 在方法攔截器中對bean2方法進行了增強
            MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
            if (var10000 == null) {
                CGLIB$BIND_CALLBACKS(this);
                var10000 = this.CGLIB$CALLBACK_0;
            }
    
            return var10000 != null ? (Bean2)var10000.intercept(this, CGLIB$bean2$1$Method, CGLIB$emptyArgs, CGLIB$bean2$1$Proxy) : super.bean2();
        }
    
        final void CGLIB$setBeanFactory$6(BeanFactory var1) throws BeansException {
            super.setBeanFactory(var1);
        }
    
        public final void setBeanFactory(BeanFactory var1) throws BeansException {
            MethodInterceptor var10000 = this.CGLIB$CALLBACK_1;
            if (var10000 == null) {
                CGLIB$BIND_CALLBACKS(this);
                var10000 = this.CGLIB$CALLBACK_1;
            }
    
            if (var10000 != null) {
                var10000.intercept(this, CGLIB$setBeanFactory$6$Method, new Object[]{var1}, CGLIB$setBeanFactory$6$Proxy);
            } else {
                super.setBeanFactory(var1);
            }
        }
    
        public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
            String var10000 = var0.toString();
            switch(var10000.hashCode()) {
                case -1792804773:
                    if (var10000.equals("bean2()Lcom/eugene/sumarry/csdn/invokeBeanFactoryPostProcessor3/Bean2;")) {
                        return CGLIB$bean2$1$Proxy;
                    }
                    break;
                case 720662557:
                    if (var10000.equals("bean1()Lcom/eugene/sumarry/csdn/invokeBeanFactoryPostProcessor3/Bean1;")) {
                        return CGLIB$bean1$0$Proxy;
                    }
                    break;
                case 2095635076:
                    if (var10000.equals("setBeanFactory(Lorg/springframework/beans/factory/BeanFactory;)V")) {
                        return CGLIB$setBeanFactory$6$Proxy;
                    }
            }
    
            return null;
        }
    
        public AppConfig$$EnhancerBySpringCGLIB$$912e823e() {
            CGLIB$BIND_CALLBACKS(this);
        }
    
        public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
            CGLIB$THREAD_CALLBACKS.set(var0);
        }
    
        public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
            CGLIB$STATIC_CALLBACKS = var0;
        }
    
        private static final void CGLIB$BIND_CALLBACKS(Object var0) {
            AppConfig$$EnhancerBySpringCGLIB$$912e823e var1 = (AppConfig$$EnhancerBySpringCGLIB$$912e823e)var0;
            if (!var1.CGLIB$BOUND) {
                var1.CGLIB$BOUND = true;
                Object var10000 = CGLIB$THREAD_CALLBACKS.get();
                if (var10000 == null) {
                    var10000 = CGLIB$STATIC_CALLBACKS;
                    if (var10000 == null) {
                        return;
                    }
                }
    
                Callback[] var10001 = (Callback[])var10000;
                var1.CGLIB$CALLBACK_2 = (NoOp)((Callback[])var10000)[2];
                var1.CGLIB$CALLBACK_1 = (MethodInterceptor)var10001[1];
                var1.CGLIB$CALLBACK_0 = (MethodInterceptor)var10001[0];
            }
    
        }
    
        static {
            CGLIB$STATICHOOK2();
            CGLIB$STATICHOOK1();
        }
    
        static void CGLIB$STATICHOOK2() {
        }
    }
    
    

三、總結

  • ConfigurationClassPostProcessorBeanFactoryPostProcessor身份最重要的就是為全注解類添加cglib代理了。當然除此之外, 還注冊了一個類型為ImportAwareBeanPostProcessorBeanPostProcessor,這里還未總結到它有何用。
  • I am a slow walker, but I never walk backwards.
  • github spring源碼學習地址: https://github.com/AvengerEug/spring/tree/develop/resourcecode-study
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容