【Spring源碼】 後置處理器BeanPostProcessor底層原理分析

注:其他一些spring源碼解讀,如果有需要,可以參考:

1.Spring中bean的生命週期

  • 今天不聊那麼複雜,其實bean的生命週期就這四步:實例化、初始化、使用、銷燬
    在這裏插入圖片描述

2.Spring註解開發指定初始化和銷燬的方式

  • 大概以下四種方式:

2.1 @Bean指定init-method和destroy-method

  • 舉例Demo:
  • bean實體類
/**
 * bean的生命週期
 *
 * @author wangjie
 * @version V1.0
 * @date 2020/1/6
 */
public class Food {

    public Food(){
        System.out.println("food constructor");
    }

    public void init(){
        System.out.println("food init");
    }

    public void detory(){
        System.out.println("food detory");
    }
}

  • 配置類
@Configuration
public class ConfigOfLifeCycle {

    @Bean(initMethod = "init",destroyMethod = "detory")
    public Food food(){
        return new Food();
    }
}
  • 測試用例:
/**
 * IOC生命週期測試
 * 注意:單實例bean測試,多實例bean容器創建完之後就不再管了
 * @author wangjie
 * @version V1.0
 * @date 2020/1/6
 */
public class IOCTest_LifeCycle {

    @Test
    public void test01(){
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ConfigOfLifeCycle.class);
        System.out.println("容器加載完成");
        applicationContext.close();
    }
}
  • 運行結果:
food constructor
food init
容器加載完成
food detory

2.2 通過讓Bean實現InitializingBean(定義初始化邏輯)DisposableBean(定義銷燬邏輯)

  • 舉例Demo:
  • bean實體類
/**
 * todo
 *
 * @author wangjie
 * @version V1.0
 * @date 2020/1/6
 */
@Component
public class Dog implements InitializingBean, DisposableBean {

    public Dog(){
        System.out.println("dog constructor");
    }
    @Override
    public void destroy() throws Exception {
        System.out.println("dog destroy");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("dog afterPropertiesSet");
    }
}

  • 配置類不變,只加上包掃描註解@ComponentScan(“com.code.bean”)
@ComponentScan("com.code.bean")
public class ConfigOfLifeCycle {...}
  • 測試用例不變,運行結果
dog constructor
dog afterPropertiesSet
food constructor
food init
容器加載完成
food detory
dog destroy

2.3 可以使用JSR250:@PostConstruct,@PreDestroy註解

  • @PostConstruct:在bean創建完成並且屬性賦值完成;來執行初始化方法

  • @PreDestroy:在容器銷燬bean之前通知我們進行清理工作

  • 舉例Demo:

  • bean實體類:

/**
 * todo
 *
 * @author wangjie
 * @version V1.0
 * @date 2020/1/6
 */
@Component
public class Pig {

    public Pig(){
        System.out.println("Pig constructor");
    }

    @PostConstruct
    public void init(){
        System.out.println("Pig PostConstruct");
    }

    @PreDestroy
    public void detory(){
        System.out.println("Pig PreDestroy");
    }
}

  • 配置類與測試用例不變,運行結果:
dog constructor
dog afterPropertiesSet
Pig constructor
Pig PostConstruct
food constructor
food init
容器加載完成
food detory
Pig PreDestroy
dog destroy

Process finished with exit code 0

2.4 主角出場,創建BeanPostProcessor接口實現類

  • BeanPostProcessor接口:bean的後置處理器,其有兩個方法
  • postProcessBeforeInitialization:在初始化之前工作
  • postProcessAfterInitialization:在初始化之後工作
  • 舉例Demo:

/**
 * todo
 *
 * @author wangjie
 * @version V1.0
 * @date 2020/1/6
 */
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {



    @Override
    public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {


        System.out.println("postProcessBeforeInitialization  "+s);
        return o;
    }

    @Override
    public Object postProcessAfterInitialization(Object o, String s) throws BeansException {

        System.out.println("postProcessAfterInitialization  "+s);
        return o;
    }
}
  • 配置類與測試用例不變,運行結果:
dog constructor
postProcessBeforeInitialization  dog
dog afterPropertiesSet
postProcessAfterInitialization  dog
Pig constructor
postProcessBeforeInitialization  pig
Pig PostConstruct
postProcessAfterInitialization  pig
food constructor
postProcessBeforeInitialization  food
food init
postProcessAfterInitialization  food
容器加載完成
food detory
Pig PreDestroy
dog destroy

Process finished with exit code 0

3.BeanPostProcessor底層原理分析

  • 這裏我們從測試用例當做入口,一點一點Debug進去:
    在這裏插入圖片描述
  • new AnnotationConfigApplicationContext(ConfigOfLifeCycle.class)創建一個IOC容器,點進去:
    在這裏插入圖片描述
  • 熟悉Spring源碼的對refresh()這個方法應該不會陌生,spring的核心,在這個方法裏,Spring完成了容器的初始化
  • 這個方法很重要,我就不截圖了,直接把 源碼搞下來一行一行添加註釋,這樣比較清楚:
public void refresh() throws BeansException, IllegalStateException {
        Object var1 = this.startupShutdownMonitor;
        synchronized(this.startupShutdownMonitor) {
            //容器刷新前的準備,設置上下文狀態,獲取屬性,驗證必要的屬性等
            this.prepareRefresh();
            //獲取新的beanFactory,銷燬原有beanFactory、爲每個bean生成BeanDefinition等
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            this.prepareBeanFactory(beanFactory);

            try {
               //配置標準的beanFactory,設置ClassLoader,設置SpEL表達式解析器,添加忽略注入的接口,添加bean,添加bean後置處理器等
                this.postProcessBeanFactory(beanFactory);
                //模板方法,此時,所有的beanDefinition已經加載,但是還沒有實例化。
                //允許在子類中對beanFactory進行擴展處理。比如添加ware相關接口自動裝配設置,添加後置處理器等,是子類擴展 
                //prepareBeanFactory(beanFactory)的方法。
                // 實例化並調用所有註冊的beanFactory後置處理器(實現接口BeanFactoryPostProcessor的bean,在beanFactory標準初始化之後執行)。
                this.invokeBeanFactoryPostProcessors(beanFactory);
                //實例化和註冊beanFactory中擴展了BeanPostProcessor的bean。
                this.registerBeanPostProcessors(beanFactory);
                //初始化國際化工具類MessageSource
                this.initMessageSource();
                //初始化事件廣播器
                this.initApplicationEventMulticaster();
                //模板方法,在容器刷新的時候可以自定義邏輯,不同的Spring容器做不同的事情。
                this.onRefresh();
                //註冊監聽器,廣播early application events
                this.registerListeners();
                //實例化所有剩餘的(非懶加載)單例
                //實例化的過程各種BeanPostProcessor開始起作用。
                this.finishBeanFactoryInitialization(beanFactory);
                //refresh做完之後需要做的其他事情。
                //清除上下文資源緩存(如掃描中的ASM元數據)
                //初始化上下文的生命週期處理器,並刷新(找出Spring容器中實現了Lifecycle接口的bean並執行start()方法)。
                //發佈ContextRefreshedEvent事件告知對應的ApplicationListener進行響應的操作
                this.finishRefresh();
            } catch (BeansException var9) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }

                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }

        }
    }
  • 註釋已經很詳細,如果想進一步看每一步詳解,可見:
  • 【spring源碼】spring容器IOC底層源碼分析
  • 我們今天聊的是註解開發和BeanPostProcessor底層原理,所以我們看的是 this.finishBeanFactoryInitialization(beanFactory);這行代碼。
  • 打開這個方法:
    在這裏插入圖片描述
  • 一堆判斷,直接看最後一行代碼,跟進去:
    在這裏插入圖片描述
  • 然後走到這個方法的getBean()裏:
    在這裏插入圖片描述
  • 再打開這個 doGetBean方法,獲取單實例的bean
    在這裏插入圖片描述
  • 獲取不到就創建:
    在這裏插入圖片描述
  • 跟進去:
    在這裏插入圖片描述
  • 再跟,找到這行:
    在這裏插入圖片描述
  • 開始初始化bean
    在這裏插入圖片描述
  • 關鍵點到了:
  • applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
  • invokeInitMethods(beanName, wrappedBean, mbd);執行自定義初始化
  • applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
  • 還記得BeanPostProcessor裏的兩個方法嗎?
  •  postProcessBeforeInitialization:在初始化之前工作
    
  •  postProcessAfterInitialization:在初始化之後工作
    
  • 仔細對比上面兩個方法看看,是不是悟出些什麼
  • 我們來看看applyBeanPostProcessorsBeforeInitialization這個方法:
    在這裏插入圖片描述
  • 遍歷執行容器內所有BeanPostProcessor接口實現類的postProcessBeforeInitialization方法。
  • 我們再來看invokeInitMethods方法
    在這裏插入圖片描述
  • 開始對bean初始化,看到我圈出的那個紅框框嗎?還記得InitializingBean接口嗎?忘記的請看上面2.2
  • 最後看一下applyBeanPostProcessorsAfterInitialization:
    在這裏插入圖片描述
  • 一脈相承,不再贅述。

4.Spring中BeanPostProcessor的應用

  • 我們直接來看Spring中BeanPostProcessor的實現類
    在這裏插入圖片描述
  • 簡單列舉幾個:

4.1 AsyncAnnotationBeanPostProcessor

  • 處理@Async註解,檢測每個bean是否符合在類級別或者方法級別使用異步註解,如果使用了,則會使用一個AsyncAnnotationAdvisor包裹該bean,從而該bean上通過異步註解所定義的方法在調用時會被真正地異步調用起來。

4.2 AbstractBeanFactoryAwareAdvisingPostProcessor

  • 可以幫助我們往組件裏面注入IOC容器,具體可以看下面Demo:
/**
 * todo
 *
 * @author wangjie
 * @version V1.0
 * @date 2020/1/6
 */
public class Car implements ApplicationContextAware {

    ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
           this.applicationContext=applicationContext;
    }
}

4.3 BeanValidationPostProcessor

  • 初始化前後的數據校驗

4.4 InitDestroyAnnotationBeanPostProcessor

  • 處理@PostConstruct,@PreDestroy註解,這兩個註解忘記做什麼的可以往上翻看2.3

4.5 AutowiredAnnotationBeanPostProcessor

  • 處理@Autowired自動依賴注入,@Autowired做什麼的不用我說了吧。。。

【完】
注:文章內所有測試用例源碼:https://gitee.com/wjie2018/source-code.git

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