這篇文章主要介紹“Spring的啟動流程介紹”,在日常操作中,相信很多人在Spring的啟動流程介紹問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Spring的啟動流程介紹”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!
創(chuàng)新互聯(lián)是專業(yè)的普寧網(wǎng)站建設(shè)公司,普寧接單;提供成都網(wǎng)站設(shè)計、成都做網(wǎng)站,網(wǎng)頁設(shè)計,網(wǎng)站設(shè)計,建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行普寧網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊,希望更多企業(yè)前來合作!
?Spring用了挺久的了,但是沒系統(tǒng)做過總結(jié),剛好前段時間在做一個Spring封裝的項目,趁機(jī)回顧了下,便基于Spring framework 4.3.22做了源碼分析。
?剛開始接觸Spring時的入門例子大致如下:
?設(shè)置配置文件路徑,初始化ApplicationContext然后獲取Bean,處理完后關(guān)閉context即可。這一節(jié)先來了解Spring的啟動過程。
?跟蹤C(jī)lassPathXmlApplicationContext的構(gòu)造方法可以看到如下內(nèi)容:
?里面設(shè)置了配置文件的路徑,并且調(diào)用了父類AbstractApplicationContext的refresh方法,該方法完成了Spring環(huán)境的初始化。如下,為refresh方法的主要過程(為方便排版,去除了原來的注釋和空格):
?下面將介紹各個方法步驟的內(nèi)容,但不進(jìn)行過多的深入,后面會單獨對每個深入的細(xì)節(jié)進(jìn)行詳細(xì)的介紹,這節(jié)先介紹大概過程。
?PrepareRefresh的內(nèi)容如上,該方法主要進(jìn)行環(huán)境的準(zhǔn)備,包括Context的啟動時間,活動狀態(tài),然后會設(shè)置context中的配置數(shù)據(jù)源,使用默認(rèn)的StandardEnvironment對象,該對象添加了System.env()屬性和System.properties()屬性。initPropertySources方法用于初始化context 中 environment的屬性源。在AbstractApplicationContext中為空實現(xiàn)。其他子類的實現(xiàn)如下:
?對于GenericWebApplicationContext和AbstractRefreshableWebApplicationContext的實現(xiàn)大致一致,都是:
?通過在getEnvironment方法中,重寫createEnvironment方法,將默認(rèn)的StandardEnvironment替換為StandardServletEnvironment, Environment的關(guān)系圖為:
?因而會執(zhí)行該類的initPropertySources方法,為context添加ServletContext和ServletConfig對應(yīng)的配置屬性源。具體的Environment中配置屬性源的加載會在后面單獨進(jìn)行介紹。
?該方法的實現(xiàn)如下,通過refreshBeanFacotry重置AbstractApplicationContext持有的BeanFacotry,然后通過getBeanFacotry獲得該對象再返回。
?AbstractApplicationContext中refreshBeanFacoty方法和getBeanFactory方法都是抽象方法,具體實現(xiàn)在AbstractRefreshableApplicationContext上。
?如上,增加了方法的注釋,重點在于loadBeanDefinitions方法,該抽象方法在具體實現(xiàn)子類上用于處理不同場景下Bean定義的加載,如Xml配置,注解配置,Web環(huán)境等,具體實現(xiàn)會在后面展開。
?目前,只是完成了Bean定義的加載,沒有出現(xiàn)Bean的實例化。
?為第2步返回的BeanFactory設(shè)置基礎(chǔ)屬性。包括:
設(shè)置ClassLoader
設(shè)置beanFactory的表達(dá)式語言處理器,默認(rèn)使用EL表達(dá)式,可以使用#{bean.xxx}的形式來調(diào)用相關(guān)屬性值
添加默認(rèn)的屬性編輯器
添加后置處理器ApplicationContextAwareProcessor,在Bean初始化后自動執(zhí)行各Aware接口的set方法,包括ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware、EnvironmentAware
添加需要忽略的依賴注入類型,這些類型會在ApplicationContextAwareProcessor中通過BeanPostProcessor后置處理,包括第(4)點涉及的各內(nèi)容
預(yù)先設(shè)置用于自動依賴注入的接口對象,包括BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext
如果存在loadTimeWeaver這個Bean,則增加對應(yīng)的后置處理器
如果不存在environment,systemProperties,systemEnvironment這3個默認(rèn)的環(huán)境屬性Bean,則注冊對應(yīng)的單例,這3個對象已經(jīng)在第1步中初始化完成
?具體可以看源碼,這步主要預(yù)先設(shè)置公共的單例Bean并添加一些公共的后置處理動作,主要體現(xiàn)在BeanPostProcessor上。
?所有Bean的定義已經(jīng)加載完成,但是沒有實例化,這一步可以修改bean定義或者增加自定義的bean,AbstractApplicationContext中為空實現(xiàn)。
?如上,以AbstractRefreshableWebApplicationContext為例,其增加了ServletContextAwareProcessor后置處理器,用于處理ServletContextAware接口和ServletConfigAware接口中相關(guān)對象的自動注入。同時新增了Web相關(guān)的應(yīng)用范圍,包括:request,session,globalSession和application,并增加了各范圍默認(rèn)的單例對象。最后增加了Web環(huán)境相關(guān)的環(huán)境配置Bean,包括servletContext,servletConfig,contextParameters和contextAttributes。
?該步驟的功能同第3步類似,都能夠增加一些后置處理器。
?在Spring容器中找出實現(xiàn)了BeanFactoryPostProcessor接口的Bean并執(zhí)行。Spring容器會委托給PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcessors方法執(zhí)行,內(nèi)容如下:
?invokeBeanFactoryPostProcessors在處理時,將BeanFactoryPostProcessor分為了兩類進(jìn)行處理,BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor,其中BeanDefinitionRegistryPostProcessor繼承自BeanFactoryPostProcessor。執(zhí)行的時候,先找出所有的BeanDefinitionRegistryPostProcessor執(zhí)行再找出所有BeanFactoryPostProcessor執(zhí)行。因為BeanDefinitionRegistryPostProcessor繼承自BeanFactoryPostProcessor,所以執(zhí)行后者時會過濾掉前者的內(nèi)容。
?在執(zhí)行BeanDefinitionRegistryPostProcessor時,會按照如下的優(yōu)先級,分類先執(zhí)行postProcessBeanDefinitionRegistry方法,再統(tǒng)一執(zhí)行所有的postProcessBeanFactory方法,,規(guī)則為:
篩選實現(xiàn)了PriorityOrdered接口的BeanDefinitionRegistryPostProcessor實現(xiàn)
篩選實現(xiàn)了Ordered接口的BeanDefinitionRegistryPostProcessor實現(xiàn),并執(zhí)行
執(zhí)行其他BeanDefinitionRegistryPostProcessors
?在執(zhí)行BeanFactoryPostProcessor也會按照如上的規(guī)則,執(zhí)行BeanFactoryPostProcessor方法。
?這里會實例化并初始化實現(xiàn)BeanFactoryPostProcessor接口的類并執(zhí)行,若存在依賴的的Bean也會被初始化和實例化,具體的過程會在介紹Bean初始化過程時說明。
?從Spring容器中找出的BeanPostProcessor接口的Bean,并添加到BeanFactory內(nèi)部維護(hù)的List屬性中,以便后續(xù)Bean被實例化的時候調(diào)用這個BeanPostProcessor進(jìn)行回調(diào)處理。該方法委托給了PostProcessorRegistrationDelegate類的registerBeanPostProcessors方法執(zhí)行。執(zhí)行過程同步驟5類似,也是按照優(yōu)先級進(jìn)行了篩選,具體順序為:
將實現(xiàn)PriorityOrdered接口的BeanPostProcessor列表注冊到ApplicationContext中
將實現(xiàn)Ordered接口的BeanPostProcessor列表注冊到ApplicationContext中
將剩余的BeanPostProcessor列表注冊到ApplicationContext中
將實現(xiàn)MergedBeanDefinitionPostProcessor接口的BeanPostProcessor列表注冊到ApplicationContext中
?其中MergedBeanDefinitionPostProcessor接口繼承自BeanPostProcessor接口,因而,上述第(4)點的列表同頭三點的列表是存在交集的。但是,AbstraceApplicationContext在添加BeanPostProcessor時,會先將存在的對象刪除,再添加新的,如下:
?因而執(zhí)行順序為因而執(zhí)行順序為:PriorityOrdered、Ordered、NotOrdered、MergedBeanDefinitionPostProcessor。
?這里會實例化并初始化實現(xiàn)BeanPostProcessor接口的類,但不執(zhí)行,若存在依賴的的Bean也會被初始化和實例化。
?在Spring容器中初始化一些國際化相關(guān)的屬性
?在Spring容器中初始化事件廣播器對象SimpleApplicationEventMulticaster,并將該對象作為單例applicationEventMulticaster注冊到Context中。該廣播器用于廣播ApplicationEvent事件對應(yīng)的ApplicationListener接口Bean。
?PS:根據(jù)以上的順序,在這之前實例化的Bean,都不會經(jīng)過BeanFactoryPostProcessor和BeanPostProcessor的處理,包括因為依賴而實例化的Bean,還有提前通過new注冊的Bean(只有直接調(diào)用BeanFactory.getBean方法獲取的bean才會進(jìn)行后置回調(diào))。這里需要注意,Context提前將兩種后置處理器的所有實現(xiàn)都提前加載了,由于實例化前需要將依賴的Bean提前實例化,所以被這兩種后置處理器依賴的Bean的初始化動作,是不會被其監(jiān)聽到的。
?模板方法,可用于refresh動作的擴(kuò)展,默認(rèn)為空實現(xiàn)。在SpringBoot中主要用于啟動內(nèi)嵌的web服務(wù)器。
?找出系統(tǒng)中的ApplicationListener對象,注冊到時間廣播器中。如果有需要提前進(jìn)行廣播的時間,則執(zhí)行廣播.
?實例化BeanFactory中已經(jīng)被注冊但是未實例化的所有實例(懶加載的不需要實例化),主要操作是BeanFacotry的preInstantiateSingletons方法。該方法分為兩部分:
遍歷已經(jīng)解析出來的所有beanDefinitionNames,如果不是抽象類、是單例且沒有設(shè)置懶加載,則進(jìn)行實例化和初始化。
在spring容器管理的所有單例對象(非懶加載對象)初始化完成之后調(diào)用SmartInitializingSingleton回調(diào)接口,注意,該回調(diào)只會發(fā)生在啟動階段,后續(xù)懶加載對象再初始化的話,不會再進(jìn)行回調(diào)
finishRefresh
?刷新后的其他動作,包括:
初始化生命周期處理器DefaultLifecycleProcessor,該處理器管理所有實現(xiàn)了Lifecycle接口的類
通知所有Lifecycle.onRefresh,該方法內(nèi)部調(diào)用LifecycleProcessor.startBeans(false),這里只會調(diào)用實現(xiàn)了SmartLifecycle接口,并且設(shè)定了AutoStartup的實例,回調(diào)將按照設(shè)定的優(yōu)先級,從低到高執(zhí)行
發(fā)布ContextRefreshedEvent通知事件
調(diào)用LiveBeansView的registerApplicationContext方法
?銷毀所有已經(jīng)注冊的單例,對于實現(xiàn)了DisposableBean的類,會先單獨進(jìn)行銷毀,以便執(zhí)行回調(diào)方法,再清理所有單例的緩存信息和剩余的單例實例
?將當(dāng)前的活動狀態(tài)標(biāo)識為false
resetCommonCaches
?清除緩存
?AbstractApplicationContext的close方法如下:
?主要是調(diào)用doClose方法,然后判斷是否有shutdownHook,如果有則移除該鉤子,避免重復(fù)關(guān)閉,因為默認(rèn)的shutdownHook也是調(diào)用的doClose方法。
?doClose方法如下:
?過程為:
去除當(dāng)前Context的MBean,如果開啟了MBean
發(fā)送ContextClosedEvent通知事件
回調(diào)聲明周期管理器的onClose方法
銷毀已經(jīng)實例化的單例,同上面提到的一致
重置BeanFacotry id為空
調(diào)用onClose方法,默認(rèn)實現(xiàn)為空,對于SpringBoot應(yīng)用,在前面說過,SpringBoot應(yīng)用重寫了onRefresh方法用于啟動web服務(wù)器,而在這里,則用于關(guān)閉內(nèi)嵌的web服務(wù)器。(PS:注意這里,web服務(wù)器的關(guān)閉是在所有Bean銷毀后再關(guān)閉的,因而在關(guān)閉服務(wù)器前,web還會接收Http請求,有可能導(dǎo)致請求無法處理,官方給了一個解決方法,詳見[issue https://github.com/spring-projects/spring-boot/issues/4657](issue https://github.com/spring-projects/spring-boot/issues/4657))
?這兩個方法來自Lifecycle接口,如下,簡單的調(diào)用了DefaultLifecycleProcessor的start和stop方法,回調(diào)Lifecycle的實現(xiàn)類。
?我們知道Spring中存在很多預(yù)設(shè)的接口,用于擴(kuò)展。通過以上分析,目前得到的回調(diào)接口順序如下:
?后續(xù)對其他細(xì)節(jié)進(jìn)行展開時,會看到更多的擴(kuò)展接口,到時再更新上面的圖。
到此,關(guān)于“Spring的啟動流程介紹”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>
網(wǎng)站標(biāo)題:Spring的啟動流程介紹
本文鏈接:http://weahome.cn/article/jpdijs.html