SpringBoot深入學(xué)習(xí)(一)-- refresh()

??springboot在啟動(dòng)的時(shí)候,會(huì)調(diào)用run方法,創(chuàng)建環(huán)境設(shè)置spring容器,其中包含refresh方法,完成配置類解析,各種beanFactoryPostProcessbeanPostProcessor注冊,web內(nèi)置容器構(gòu)造,國際化配置初始化等,refresh調(diào)用了父類AbstractApplicationContextrefresh方法如下。

@Override
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
    // 準(zhǔn)備,記錄容器的啟動(dòng)時(shí)間startupDate, 標(biāo)記容器為激活,初始化上下文環(huán)境如文件路徑信息,驗(yàn)證必填屬性是否填寫 
    prepareRefresh();

    // 這步比較重要(解析),告訴子類去刷新bean工廠,這步完成后配置文件就解析成一個(gè)個(gè)bean定義,注冊到BeanFactory(但是未被初始化,僅將信息寫到了beanDefination的map中)
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
 
    // 設(shè)置beanFactory類加載器,添加多個(gè)beanPostProcesser
    prepareBeanFactory(beanFactory);
 
    try {
        // 允許子類上下文中對beanFactory做后期處理
        postProcessBeanFactory(beanFactory);
 
        // 調(diào)用BeanFactoryPostProcessor各個(gè)實(shí)現(xiàn)類的方法
        invokeBeanFactoryPostProcessors(beanFactory);
 
        // 注冊 BeanPostProcessor 的實(shí)現(xiàn)類,注意看和 BeanFactoryPostProcessor 的區(qū)別
         // 此接口兩個(gè)方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
         // 兩個(gè)方法分別在 Bean 初始化之前和初始化之后得到執(zhí)行。注意,到這里 Bean 還沒初始化
        registerBeanPostProcessors(beanFactory);
 
        //初始化ApplicationContext的MessageSource
        initMessageSource();
 
        //初始化ApplicationContext事件廣播器
        initApplicationEventMulticaster();
 
        // 初始化子類特殊bean(鉤子方法)
        onRefresh();
 
        // 注冊事件監(jiān)聽器
        registerListeners();
 
        // 初始化所有singleton bean  重點(diǎn)!!重點(diǎn)!!
        finishBeanFactoryInitialization(beanFactory);
 
        // 廣播事件,ApplicationContext初始化完成
        finishRefresh();
} catch (BeansException ex) {
....................
}
image

1. prepareRefresh()

??在rehresh之前做的準(zhǔn)備工作,一是設(shè)置spring啟動(dòng)事件,開啟活躍狀態(tài);二是初始化屬性源信息;三是驗(yàn)證必要屬性。

image

1.1 initPropertySources()

??在應(yīng)用啟動(dòng)之前替換一些屬性占位符,這個(gè)方法再Spring的對象中一般都沒有實(shí)現(xiàn),應(yīng)該是用來方便我們后期擴(kuò)展使用的方法。

1.2 validateRequiredProperties()

??Environment類的方法驗(yàn)證必須的屬性是否正確。

2. obtainFreshBeanFactory();

??獲取新的beanFactory,銷毀原有beanFactory、為每個(gè)bean生成BeanDefinition
??obtainFreshBeanFactory方法從字面的意思看獲取新的Bean工廠,實(shí)際上這是一個(gè)過程,一個(gè)加載Xml資源并解析,根據(jù)解析結(jié)果組裝BeanDefinitions,然后初始化BeanFactory的過程。如下圖跳入方法源碼中

image

2.1 refreshBeanFactory()

??refreshBeanFactory是具體的刷新BeanFactory,負(fù)責(zé)這個(gè)工作做在類AbstractRefreshableApplicationContext中,顧名思義這是專門用來刷新的。

image

詳細(xì)說明:

  1. 首先判斷,是否存在BeanFactory,如果存在容器beanFactory,則先銷毀所有的bean,然后關(guān)閉beanFactory
  2. DefaultListableBeanFactory beanFactory = createBeanFactory(); 創(chuàng)建初始容器beanFactory,此處創(chuàng)建的是DefaultListableBaenFactory,是最重要的beanFactory,即初始化容器;spring注冊&加載bean的基本容器;
    image
  3. customizeBeanFactory(beanFactory);根據(jù)AbstractRefreshableApplicationContext類的屬性為Beanfactory設(shè)置屬性值。
    image

    allowBeanDefinitionOverriding:屬性是指是否允對一個(gè)名字相同但definition不同進(jìn)行重新注冊,默認(rèn)是true。 allowCircularReferences屬性是指是否允許Bean之間循環(huán)引用,默認(rèn)是true
    默認(rèn)兩個(gè)屬性都為空,可擴(kuò)展的,可以自己設(shè)置屬性,方法就是繼承ClassPathXmlApplicationContext并復(fù)寫customizeBeanFactory方法為兩個(gè)屬性設(shè)置值即可。
  4. loadBeanDefinitions(beanFactory);BeanDenifition注冊到bean工廠
    [圖片上傳失敗...(image-e0509-1560845367203)]查看最后一個(gè)方法:
    loadBeanDefinitions(beanDefinitionReader);
    image

    例如:applicationContext.xml不是在calsspath下了,只有Resource,那怎么辦,直接傳遞進(jìn)來即可,繼承ClassPathXmlApplicationContext類重寫getConfigResources方法,返回Resource即可。

3. prepareBeanFactory();

??在ApplicationContext刷新獲取beanFactory之后,開始準(zhǔn)備context使用的beanFactory。這一步相對比較簡單,就是配置beanFacotry的特性

  1. beanFactory.setBeanClassLoader(getClassLoader());設(shè)置類加載器;設(shè)置BeanFactoryBeanClassLoader,如果存在,則直接使用之前的那個(gè),否則,初始化一個(gè)新的ClassLoader;

    image

  2. beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));設(shè)置BeanExpressionResolver表達(dá)式解析器,主要用來解析EL表達(dá)式;Bean初始化完成后填充屬性時(shí)會(huì)用到

  3. beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));設(shè)置屬性注冊解析器PropertyEditor;這個(gè)主要是對某些注入的Bean的一些屬性的支持;

  4. beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor (this));此處添加了一個(gè)BeanPostProcessor實(shí)現(xiàn):ApplicationContextAwareProcessor,它是用來處理并回調(diào)實(shí)現(xiàn)了各種Aware接口的Bean,比如獲取ApplicationContext的ApplicationContextAware接口。添加BeanPostProcessor(Bean后置處理器ApplicationContextAwareProcessor),當(dāng)bean被這個(gè)工廠創(chuàng)建的時(shí)候會(huì)用到PostProcessor, 在beanfactory中存儲了beanPostProcessors的列表,在生效的時(shí)候,列表中的PostProcessor都會(huì)執(zhí)行。 在bean初始化之前,調(diào)用ApplicationContextAwareProcessorpostProcessBeforeInitialization處理所有的Aware接口,進(jìn)行如下操作:

    // 如果bean實(shí)現(xiàn)了EmbeddedValueResolverAware接口,調(diào)用bean.setEmbeddedValueResolver
    // 如果bean實(shí)現(xiàn)了ResourceLoaderAware接口,調(diào)用bean.setResourceLoader
    // 如果bean實(shí)現(xiàn)了ApplicationEventPublisherAware接口,調(diào)用bean.setApplicationEventPublisher
    // 如果bean實(shí)現(xiàn)了MessageSourceAware接口,調(diào)用bean.setMessageSource
    // 如果bean實(shí)現(xiàn)了ApplicationContextAware接口,調(diào)用bean.setApplicationContext
  1. beanFactory.ignoreDependencyInterface()指定的接口不會(huì)被自動(dòng)注入進(jìn)去。
  2. beanFactory.registerResolvableDependency()設(shè)置幾個(gè)自動(dòng)裝配規(guī)則,例如BeanFactory則注入beanFactory ResourceLoader,ApplicationEventPublisher,ApplicationContext注入當(dāng)前對象
    image
  3. beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)如果當(dāng)前BeanFactory包含loadTimeWeaver Bean,說明存在類加載期織入AspectJ,則把當(dāng)前BeanFactory交給類加載期BeanPostProcessor實(shí)現(xiàn)類LoadTimeWeaverAwareProcessor來處理,從而實(shí)現(xiàn)類加載期織入AspectJ的目的。
    image
  4. 注冊當(dāng)前容器環(huán)境environment組件Bean
    [圖片上傳失敗...(image-edc8e7-1560845367203)]
  5. 注冊系統(tǒng)配置systemProperties組件Bean
    image
  6. 注冊系統(tǒng)環(huán)境systemEnvironment組件Bean
    image

??總結(jié):
(1)設(shè)置類加載器 (2)設(shè)置EL表達(dá)式解析器(bean創(chuàng)建完成填充屬性時(shí)使用)和屬性注冊解析器 (3)利用beanPostProcessor的特性給各種Aware接口的實(shí)現(xiàn)類注入ApplicationContext中對應(yīng)的屬性; (4)設(shè)置各種Aware接口的實(shí)現(xiàn)類為忽略自動(dòng)裝配 (5)設(shè)置自動(dòng)裝配類(BeanFactory,ResourceLoader,ApplicationEventPublisher,ApplicationContext) (6)如果BeanFactory中存在loadTimeWeaver的bean,那么需要添加動(dòng)態(tài)織入功能 (7).注冊各種可用組件(environment,systemProperties,systemEnvironment)

4.postProcessBeanFactory()

??bean工廠的bean屬性處理容器,說通俗一些就是可以管理我們的bean工廠內(nèi)所有的beandefinition(未實(shí)例化)數(shù)據(jù);
??postProcessBeanFactory后處理beanFactory。時(shí)機(jī)是在所有的beanDenifition加載完成之后,bean實(shí)例化之前執(zhí)行。
??比如,在beanfactory加載完成所有的bean后,想修改其中某個(gè)bean的定義,或者對beanFactory做一些其他的配置,就可以用此方法。在系列文章中,可以實(shí)現(xiàn)ClassPathXmlApplicationContext類并重寫postProcessBeanFactory即可。

默認(rèn)情況下此方法是空的。需要子類去實(shí)現(xiàn)
注意:
BeanFactoryPostProcessor的主要作用是讓你能接觸到bean definitions,對bean definitions進(jìn)行一定hack,但是也僅此而已了。絕對不允許在BeanFactoryPostProcessor中觸發(fā)到bean的實(shí)例化!
舉例:

@Component
public class PrematureBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        Map<String, BBean> map = beanFactory.getBeansOfType(BBean.class);
        for (BBean bBean : map.values()) {
            assert bBean.getABean() == null;
        }
    }
}

@Component("bBean")
public class BBean {

    @Autowired
    private ABean aBean;

    public ABean getABean() {
        return aBean;
    }

}

@Component
public class ABean {

    private String name = "a";

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

??在運(yùn)行后,BBean中被期待注入的ABean最終為null。這是為啥呢?postProcessBeanFactory(beanFactory); 首先invoke了容器中的BeanFactoryPostProcessor實(shí)現(xiàn)類,其中當(dāng)然就包括PrematureBeanFactoryPostProcessor,此時(shí)通過beanFactory.getBeansOfType觸發(fā)了bean提前實(shí)例化。按理說,bean提前實(shí)例化也應(yīng)該沒問題的,aBean也應(yīng)該是能夠被注入的呀!那為啥最終不是這個(gè)結(jié)果呢?
??從源碼可知:
@AutoWired起作用依賴AutowiredAnnotationBeanPostProcessor
@Resource依賴CommonAnnotationBeanPostProcessor,這倆都是BeanPostProcessor的實(shí)現(xiàn)。
??那BeanPostProcessors在何處被spring invoke呢?
參見refresh()方法registerBeanPostProcessors(beanFactory);
postProcessBeanFactory(beanFactory);后面被調(diào)用;
??也就是說BBean被觸發(fā)提前初始化的時(shí)候,AutowiredAnnotationBeanPostProcessor還沒有被注冊自然也不會(huì)被執(zhí)行到,自然ABean=null

5.invokeBeanFactoryPostProcessors(beanFactory);

??實(shí)例化Factory之前預(yù)處理部分
??invokeBeanFactoryPostProcessors 方法主要用于處理 BeanFactoryPostProcessor 接口。BeanFactoryPostProcessor 接口是 Spring 初始化 Bean 時(shí)對外暴露的擴(kuò)展點(diǎn),Spring IoC 容器允許 BeanFactoryPostProcessor 在容器實(shí)例化任何 Bean 之前讀取Bean 的定義,并可以修改它。
??可以理解為,初始化我們自定義的BeanFactoryPostProcessor
postProcessBeanFactory用于在標(biāo)準(zhǔn)的初始化完成后修改容器上下文中的beanFactory。所有bean定義將被加載,但是它們將暫時(shí)不被實(shí)例化,這允許覆蓋,甚至添加一些屬性到延遲初始化的bean上。也就是說,允許我們開發(fā)者自定義的去修改BeanFactory中的內(nèi)容,這也是符合“spring”的開閉原則。invokeBeanFactoryPostProcessors,就是調(diào)用postProcessBeanFactory

image

5.1. getBeanFactoryPostProcessors()

??獲取的手動(dòng)注冊的BeanFactoryPostProcessor;
??是通過beanFactory.addBeanPostProcessor()方法設(shè)置的BeanFactoryPostProcessor。默認(rèn)空的,因?yàn)闆]有通過addBeanFactoryPostProcessor方法添加BeanFactoryPostProcessor

image

5.2 PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()

未完待續(xù)...

6. registerBeanPostProcessors(beanFactory);

注冊BeanPostProcessor
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

image

image

注冊BeanPostProcessorinvokeBeanFactoryPostProcessors很像,并且沒什么復(fù)雜邏輯。就是將已經(jīng)注冊到beanFacory的Bean篩選出BeanPostProcessor然后添加到ApplicationContextbeanPostProcessor集合中。
主要邏輯:

  1. :首先在容器中注冊一個(gè)BeanPostProcessorChecker,這個(gè)只是用來對在bean不適合所有的BeanPostProcessor調(diào)用的情況下,打印一些日志信息。

  2. :先注冊實(shí)現(xiàn)了PriorityOrdered接口的BeanPostProcessor,再注冊實(shí)現(xiàn)了Ordered接口的的BeanPostProcessor,然后注冊什么接口都沒實(shí)現(xiàn)的BeanPostProcessor,最后注冊實(shí)現(xiàn)了MergedBeanDefinitionPostProcessor接口的BeanPostProcessor

  3. :注冊ApplicationListenerDetector。用來檢測bean是否是ApplicationListener,如果是判斷是否是單例,如果不是單例,那么刪除singtonNames中對應(yīng)的key

7. initMessageSource();初始化消息源

為本context初始化消息源;
判斷beanFactory中是否有名字為messageSource的bean,如果有,從beanFactory中獲取并且判斷獲取的是不是HierarchicalMessageSource類型的,如果是設(shè)置其父級消息源;如果沒有,新建DelegatingMessageSource類作為messageSource的Bean。

image

8. initApplicationEventMulticaster();初始化應(yīng)用事件廣播器

初始化ApplicationEventMulticaster
首先判斷beanFactory容器中是否存在這個(gè)廣播器:applicationEventMulticaster
如果存在,則用beanFactory中的bean;如果不存在則使用新建SimpleApplicationEventMulticaster

image

9. onRefresh();

10. registerListeners();注冊監(jiān)聽器

在發(fā)布事件的時(shí)候會(huì)從這里注冊的監(jiān)聽器中去獲取;


image

11.finishBeanFactoryInitialization(beanFactory);

完成此上下文的 bean 工廠的初始化,初始化所有剩余的單例 bean。實(shí)例化所有的非懶加載單例。是ApplicationContext刷新的時(shí)候,最重要的方法了,因?yàn)樗械腷ean,如果不是lazy-init的都會(huì)在這一步進(jìn)行實(shí)例化,并且做一些處理。

image

12.finishRefresh();

完成對context的刷新

13.總結(jié)

1.prepareRefresh();對刷新進(jìn)行準(zhǔn)備,包括設(shè)置開始時(shí)間,設(shè)置激活狀態(tài),初始化Context中的占位符,子類根據(jù)其需求執(zhí)行具體準(zhǔn)備工作,而后再由父類驗(yàn)證必要參數(shù)

2.obtianFreshBeanFactory();,刷新并獲取內(nèi)部的BeanFactory對象

3.prepareBeanFactory(beanFactory);,對BeanFactory進(jìn)行準(zhǔn)備工作,包括設(shè)置類加載器和后置處理器,配置不能自動(dòng)裝配的類型,注冊默認(rèn)的環(huán)境Bean

4.postProcessBeanFactory(beanFactory);為Context的子類提供后置處理BeanFactory的擴(kuò)展能力,如想在bean定義加載完成后,開始初始化上下文之前進(jìn)行邏輯操作,可重寫這個(gè)方法

5.invokeBeanFactoryPostProcessors(beanFactory);,執(zhí)行Context中注冊的BeanFactory后置處理器,有兩張?zhí)幚砥?一種是可以注冊Bean的后置處理器,一種的針對BeanFactory的后置處理器,執(zhí)行順序是先按優(yōu)先級執(zhí)行注冊Bean的后置處理器,而后再按優(yōu)先級執(zhí)行針對BeanFactory的后置處理器

SpringBoot中會(huì)進(jìn)行注解Bean的解析,由ConfigurationClassPostProcessor觸發(fā),由ClassPathDefinitionScanner解析,并注冊到BeanFactory

6.registerBeanFactoryProcessor(beanFactory();,按優(yōu)先級順序在BeanFactory中注冊Bean的后置處理器,Bean處理器可在Bean的初始化前后處理
7.initMessageSource();初始化消息源,消息源用于支持消息的國際化

8.initApplicationEventMuticaster();初始化應(yīng)用事件廣播器,用于向ApplicationListener通知各種應(yīng)用產(chǎn)生的事件,標(biāo)準(zhǔn)的觀察者模型

9.onRefresh();,用于子類的擴(kuò)展步驟,用于特定的Context子類初始化其他的Bean

10.registerListeners();,把實(shí)現(xiàn)了ApplicationListener的類注冊到廣播器,并對廣播其中早期沒有廣播的事件進(jìn)行通知

11.finishBeanFactoryInitialization(beanFactory);,凍結(jié)所有Bean描述信息的修改,實(shí)例化非延遲加載的單例Bean

12.finishRefresh();,完成上下文的刷新工作,調(diào)用LifecycleProcessor.onRefresh(),以及發(fā)布

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容