溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Spring的啟動(dòng)流程介紹

發(fā)布時(shí)間:2021-06-26 15:02:05 來源:億速云 閱讀:155 作者:chen 欄目:大數(shù)據(jù)

這篇文章主要介紹“Spring的啟動(dòng)流程介紹”,在日常操作中,相信很多人在Spring的啟動(dòng)流程介紹問題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”Spring的啟動(dòng)流程介紹”的疑惑有所幫助!接下來,請(qǐng)跟著小編一起來學(xué)習(xí)吧!

?Spring用了挺久的了,但是沒系統(tǒng)做過總結(jié),剛好前段時(shí)間在做一個(gè)Spring封裝的項(xiàng)目,趁機(jī)回顧了下,便基于Spring framework 4.3.22做了源碼分析。

?剛開始接觸Spring時(shí)的入門例子大致如下:

Spring的啟動(dòng)流程介紹

?設(shè)置配置文件路徑,初始化ApplicationContext然后獲取Bean,處理完后關(guān)閉context即可。這一節(jié)先來了解Spring的啟動(dòng)過程。

一. 啟動(dòng)

?跟蹤C(jī)lassPathXmlApplicationContext的構(gòu)造方法可以看到如下內(nèi)容:

Spring的啟動(dòng)流程介紹

?里面設(shè)置了配置文件的路徑,并且調(diào)用了父類AbstractApplicationContext的refresh方法,該方法完成了Spring環(huán)境的初始化。如下,為refresh方法的主要過程(為方便排版,去除了原來的注釋和空格):

Spring的啟動(dòng)流程介紹

?下面將介紹各個(gè)方法步驟的內(nèi)容,但不進(jìn)行過多的深入,后面會(huì)單獨(dú)對(duì)每個(gè)深入的細(xì)節(jié)進(jìn)行詳細(xì)的介紹,這節(jié)先介紹大概過程。

1.1. try

1.prepareRefresh

Spring的啟動(dòng)流程介紹

?PrepareRefresh的內(nèi)容如上,該方法主要進(jìn)行環(huán)境的準(zhǔn)備,包括Context的啟動(dòng)時(shí)間,活動(dòng)狀態(tài),然后會(huì)設(shè)置context中的配置數(shù)據(jù)源,使用默認(rèn)的StandardEnvironment對(duì)象,該對(duì)象添加了System.env()屬性和System.properties()屬性。initPropertySources方法用于初始化context 中 environment的屬性源。在AbstractApplicationContext中為空實(shí)現(xiàn)。其他子類的實(shí)現(xiàn)如下:

Spring的啟動(dòng)流程介紹

?對(duì)于GenericWebApplicationContext和AbstractRefreshableWebApplicationContext的實(shí)現(xiàn)大致一致,都是:

Spring的啟動(dòng)流程介紹

?通過在getEnvironment方法中,重寫createEnvironment方法,將默認(rèn)的StandardEnvironment替換為StandardServletEnvironment, Environment的關(guān)系圖為:

Spring的啟動(dòng)流程介紹

?因而會(huì)執(zhí)行該類的initPropertySources方法,為context添加ServletContext和ServletConfig對(duì)應(yīng)的配置屬性源。具體的Environment中配置屬性源的加載會(huì)在后面單獨(dú)進(jìn)行介紹。

2.obtainFreshBeanFactory

?該方法的實(shí)現(xiàn)如下,通過refreshBeanFacotry重置AbstractApplicationContext持有的BeanFacotry,然后通過getBeanFacotry獲得該對(duì)象再返回。

Spring的啟動(dòng)流程介紹

?AbstractApplicationContext中refreshBeanFacoty方法和getBeanFactory方法都是抽象方法,具體實(shí)現(xiàn)在AbstractRefreshableApplicationContext上。

Spring的啟動(dòng)流程介紹

?如上,增加了方法的注釋,重點(diǎn)在于loadBeanDefinitions方法,該抽象方法在具體實(shí)現(xiàn)子類上用于處理不同場(chǎng)景下Bean定義的加載,如Xml配置,注解配置,Web環(huán)境等,具體實(shí)現(xiàn)會(huì)在后面展開。

?目前,只是完成了Bean定義的加載,沒有出現(xiàn)Bean的實(shí)例化。

3.prepareBeanFactory

?為第2步返回的BeanFactory設(shè)置基礎(chǔ)屬性。包括:

  1. 設(shè)置ClassLoader

  2. 設(shè)置beanFactory的表達(dá)式語言處理器,默認(rèn)使用EL表達(dá)式,可以使用#{bean.xxx}的形式來調(diào)用相關(guān)屬性值

  3. 添加默認(rèn)的屬性編輯器

  4. 添加后置處理器ApplicationContextAwareProcessor,在Bean初始化后自動(dòng)執(zhí)行各Aware接口的set方法,包括ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware、EnvironmentAware

  5. 添加需要忽略的依賴注入類型,這些類型會(huì)在ApplicationContextAwareProcessor中通過BeanPostProcessor后置處理,包括第(4)點(diǎn)涉及的各內(nèi)容

  6. 預(yù)先設(shè)置用于自動(dòng)依賴注入的接口對(duì)象,包括BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext

  7. 如果存在loadTimeWeaver這個(gè)Bean,則增加對(duì)應(yīng)的后置處理器

  8. 如果不存在environment,systemProperties,systemEnvironment這3個(gè)默認(rèn)的環(huán)境屬性Bean,則注冊(cè)對(duì)應(yīng)的單例,這3個(gè)對(duì)象已經(jīng)在第1步中初始化完成

?具體可以看源碼,這步主要預(yù)先設(shè)置公共的單例Bean并添加一些公共的后置處理動(dòng)作,主要體現(xiàn)在BeanPostProcessor上。

4.postProcessBeanFactory

?所有Bean的定義已經(jīng)加載完成,但是沒有實(shí)例化,這一步可以修改bean定義或者增加自定義的bean,AbstractApplicationContext中為空實(shí)現(xiàn)。

Spring的啟動(dòng)流程介紹

?如上,以AbstractRefreshableWebApplicationContext為例,其增加了ServletContextAwareProcessor后置處理器,用于處理ServletContextAware接口和ServletConfigAware接口中相關(guān)對(duì)象的自動(dòng)注入。同時(shí)新增了Web相關(guān)的應(yīng)用范圍,包括:request,session,globalSession和application,并增加了各范圍默認(rèn)的單例對(duì)象。最后增加了Web環(huán)境相關(guān)的環(huán)境配置Bean,包括servletContext,servletConfig,contextParameters和contextAttributes。

?該步驟的功能同第3步類似,都能夠增加一些后置處理器。

5.invokeBeanFactoryPostProcessors

?在Spring容器中找出實(shí)現(xiàn)了BeanFactoryPostProcessor接口的Bean并執(zhí)行。Spring容器會(huì)委托給PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcessors方法執(zhí)行,內(nèi)容如下:

Spring的啟動(dòng)流程介紹

?invokeBeanFactoryPostProcessors在處理時(shí),將BeanFactoryPostProcessor分為了兩類進(jìn)行處理,BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor,其中BeanDefinitionRegistryPostProcessor繼承自BeanFactoryPostProcessor。執(zhí)行的時(shí)候,先找出所有的BeanDefinitionRegistryPostProcessor執(zhí)行再找出所有BeanFactoryPostProcessor執(zhí)行。因?yàn)锽eanDefinitionRegistryPostProcessor繼承自BeanFactoryPostProcessor,所以執(zhí)行后者時(shí)會(huì)過濾掉前者的內(nèi)容。

?在執(zhí)行BeanDefinitionRegistryPostProcessor時(shí),會(huì)按照如下的優(yōu)先級(jí),分類先執(zhí)行postProcessBeanDefinitionRegistry方法,再統(tǒng)一執(zhí)行所有的postProcessBeanFactory方法,,規(guī)則為:

  1. 篩選實(shí)現(xiàn)了PriorityOrdered接口的BeanDefinitionRegistryPostProcessor實(shí)現(xiàn)

  2. 篩選實(shí)現(xiàn)了Ordered接口的BeanDefinitionRegistryPostProcessor實(shí)現(xiàn),并執(zhí)行

  3. 執(zhí)行其他BeanDefinitionRegistryPostProcessors

?在執(zhí)行BeanFactoryPostProcessor也會(huì)按照如上的規(guī)則,執(zhí)行BeanFactoryPostProcessor方法。

?這里會(huì)實(shí)例化并初始化實(shí)現(xiàn)BeanFactoryPostProcessor接口的類并執(zhí)行,若存在依賴的的Bean也會(huì)被初始化和實(shí)例化,具體的過程會(huì)在介紹Bean初始化過程時(shí)說明。

6.registerBeanPostProcessors

?從Spring容器中找出的BeanPostProcessor接口的Bean,并添加到BeanFactory內(nèi)部維護(hù)的List屬性中,以便后續(xù)Bean被實(shí)例化的時(shí)候調(diào)用這個(gè)BeanPostProcessor進(jìn)行回調(diào)處理。該方法委托給了PostProcessorRegistrationDelegate類的registerBeanPostProcessors方法執(zhí)行。執(zhí)行過程同步驟5類似,也是按照優(yōu)先級(jí)進(jìn)行了篩選,具體順序?yàn)椋?/p>

  1. 將實(shí)現(xiàn)PriorityOrdered接口的BeanPostProcessor列表注冊(cè)到ApplicationContext中

  2. 將實(shí)現(xiàn)Ordered接口的BeanPostProcessor列表注冊(cè)到ApplicationContext中

  3. 將剩余的BeanPostProcessor列表注冊(cè)到ApplicationContext中

  4. 將實(shí)現(xiàn)MergedBeanDefinitionPostProcessor接口的BeanPostProcessor列表注冊(cè)到ApplicationContext中

?其中MergedBeanDefinitionPostProcessor接口繼承自BeanPostProcessor接口,因而,上述第(4)點(diǎn)的列表同頭三點(diǎn)的列表是存在交集的。但是,AbstraceApplicationContext在添加BeanPostProcessor時(shí),會(huì)先將存在的對(duì)象刪除,再添加新的,如下:

Spring的啟動(dòng)流程介紹

?因而執(zhí)行順序?yàn)橐蚨鴪?zhí)行順序?yàn)?PriorityOrdered、Ordered、NotOrdered、MergedBeanDefinitionPostProcessor。

?這里會(huì)實(shí)例化并初始化實(shí)現(xiàn)BeanPostProcessor接口的類,但不執(zhí)行,若存在依賴的的Bean也會(huì)被初始化和實(shí)例化。

7.initMessageSource

?在Spring容器中初始化一些國(guó)際化相關(guān)的屬性

8.initApplicationEventMulticaster

?在Spring容器中初始化事件廣播器對(duì)象SimpleApplicationEventMulticaster,并將該對(duì)象作為單例applicationEventMulticaster注冊(cè)到Context中。該廣播器用于廣播ApplicationEvent事件對(duì)應(yīng)的ApplicationListener接口Bean。

?PS:根據(jù)以上的順序,在這之前實(shí)例化的Bean,都不會(huì)經(jīng)過BeanFactoryPostProcessor和BeanPostProcessor的處理,包括因?yàn)橐蕾嚩鴮?shí)例化的Bean,還有提前通過new注冊(cè)的Bean(只有直接調(diào)用BeanFactory.getBean方法獲取的bean才會(huì)進(jìn)行后置回調(diào))。這里需要注意,Context提前將兩種后置處理器的所有實(shí)現(xiàn)都提前加載了,由于實(shí)例化前需要將依賴的Bean提前實(shí)例化,所以被這兩種后置處理器依賴的Bean的初始化動(dòng)作,是不會(huì)被其監(jiān)聽到的。

9.onRefresh

?模板方法,可用于refresh動(dòng)作的擴(kuò)展,默認(rèn)為空實(shí)現(xiàn)。在SpringBoot中主要用于啟動(dòng)內(nèi)嵌的web服務(wù)器。

10.registerListeners

?找出系統(tǒng)中的ApplicationListener對(duì)象,注冊(cè)到時(shí)間廣播器中。如果有需要提前進(jìn)行廣播的時(shí)間,則執(zhí)行廣播.

11.finishBeanFactoryInitialization

?實(shí)例化BeanFactory中已經(jīng)被注冊(cè)但是未實(shí)例化的所有實(shí)例(懶加載的不需要實(shí)例化),主要操作是BeanFacotry的preInstantiateSingletons方法。該方法分為兩部分:

  1. 遍歷已經(jīng)解析出來的所有beanDefinitionNames,如果不是抽象類、是單例且沒有設(shè)置懶加載,則進(jìn)行實(shí)例化和初始化。

  2. 在spring容器管理的所有單例對(duì)象(非懶加載對(duì)象)初始化完成之后調(diào)用SmartInitializingSingleton回調(diào)接口,注意,該回調(diào)只會(huì)發(fā)生在啟動(dòng)階段,后續(xù)懶加載對(duì)象再初始化的話,不會(huì)再進(jìn)行回調(diào)

  3. finishRefresh

?刷新后的其他動(dòng)作,包括:

  1. 初始化生命周期處理器DefaultLifecycleProcessor,該處理器管理所有實(shí)現(xiàn)了Lifecycle接口的類

  2. 通知所有Lifecycle.onRefresh,該方法內(nèi)部調(diào)用LifecycleProcessor.startBeans(false),這里只會(huì)調(diào)用實(shí)現(xiàn)了SmartLifecycle接口,并且設(shè)定了AutoStartup的實(shí)例,回調(diào)將按照設(shè)定的優(yōu)先級(jí),從低到高執(zhí)行

  3. 發(fā)布ContextRefreshedEvent通知事件

  4. 調(diào)用LiveBeansView的registerApplicationContext方法

1.2. catch

1.destroyBeans

?銷毀所有已經(jīng)注冊(cè)的單例,對(duì)于實(shí)現(xiàn)了DisposableBean的類,會(huì)先單獨(dú)進(jìn)行銷毀,以便執(zhí)行回調(diào)方法,再清理所有單例的緩存信息和剩余的單例實(shí)例

2.cancelRefresh

?將當(dāng)前的活動(dòng)狀態(tài)標(biāo)識(shí)為false

1.3. finally
  1. resetCommonCaches

?清除緩存

二. 關(guān)閉

?AbstractApplicationContext的close方法如下:

Spring的啟動(dòng)流程介紹

?主要是調(diào)用doClose方法,然后判斷是否有shutdownHook,如果有則移除該鉤子,避免重復(fù)關(guān)閉,因?yàn)槟J(rèn)的shutdownHook也是調(diào)用的doClose方法。

?doClose方法如下:

Spring的啟動(dòng)流程介紹

?過程為:

  1. 去除當(dāng)前Context的MBean,如果開啟了MBean

  2. 發(fā)送ContextClosedEvent通知事件

  3. 回調(diào)聲明周期管理器的onClose方法

  4. 銷毀已經(jīng)實(shí)例化的單例,同上面提到的一致

  5. 重置BeanFacotry id為空

  6. 調(diào)用onClose方法,默認(rèn)實(shí)現(xiàn)為空,對(duì)于SpringBoot應(yīng)用,在前面說過,SpringBoot應(yīng)用重寫了onRefresh方法用于啟動(dòng)web服務(wù)器,而在這里,則用于關(guān)閉內(nèi)嵌的web服務(wù)器。(PS:注意這里,web服務(wù)器的關(guān)閉是在所有Bean銷毀后再關(guān)閉的,因而在關(guān)閉服務(wù)器前,web還會(huì)接收Http請(qǐng)求,有可能導(dǎo)致請(qǐng)求無法處理,官方給了一個(gè)解決方法,詳見[issue https://github.com/spring-projects/spring-boot/issues/4657](issue https://github.com/spring-projects/spring-boot/issues/4657))

三. Start Stop方法

?這兩個(gè)方法來自Lifecycle接口,如下,簡(jiǎn)單的調(diào)用了DefaultLifecycleProcessor的start和stop方法,回調(diào)Lifecycle的實(shí)現(xiàn)類。

Spring的啟動(dòng)流程介紹

Spring的啟動(dòng)流程介紹

四. 擴(kuò)展接口順序

?我們知道Spring中存在很多預(yù)設(shè)的接口,用于擴(kuò)展。通過以上分析,目前得到的回調(diào)接口順序如下:

Spring的啟動(dòng)流程介紹

?后續(xù)對(duì)其他細(xì)節(jié)進(jìn)行展開時(shí),會(huì)看到更多的擴(kuò)展接口,到時(shí)再更新上面的圖。

到此,關(guān)于“Spring的啟動(dòng)流程介紹”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI