SpringBoot啟動(dòng)流程淺析

基于SpringBoot 2.1.5

SpringBootSpring Framework的基礎(chǔ)上增加的自動(dòng)配置(約定優(yōu)于配置)特性能夠讓開(kāi)發(fā)人員更少的關(guān)注底層而帶來(lái)更快的開(kāi)發(fā)速度。但是由此帶來(lái)的弊端是開(kāi)發(fā)人員過(guò)于依賴完善的框架功能而沒(méi)有去深入細(xì)節(jié)蜕青,只知其然而不知其所以然市咆。由此記錄一下最近在讀的SpringBoot的源碼并記錄一下SpringBoot的啟動(dòng)流程

SpringBoot的啟動(dòng)邏輯在SpringApplication這個(gè)類中蒙兰,通過(guò)構(gòu)造一個(gè)SpringApplication并調(diào)用run方法啟動(dòng)SpringBoot應(yīng)用程序搜变。SpringBoot啟動(dòng)后的主要流程:

  1. 設(shè)置webApplicationType(web應(yīng)用類型)
    webApplicationType是啟動(dòng)流程中一個(gè)比較重要的屬性挠他,SpringBoot根據(jù)它的類型來(lái)創(chuàng)建Environment對(duì)象和應(yīng)用上下文對(duì)象(ApplicationContext)

  2. 準(zhǔn)備應(yīng)用上下文環(huán)境(Environment)
    根據(jù)上一步推斷的webApplicationType創(chuàng)建不同類型的Environment殖侵,并且將用戶的profile文件讀取到Environment中

  3. 讀取profile

  4. 創(chuàng)建并配置應(yīng)用上下文對(duì)象(ApplicationContext)
    根據(jù)webApplicationType創(chuàng)建不同實(shí)現(xiàn)的ApplicationContext

  5. 刷新應(yīng)用上下文對(duì)象(refresh)
    AbstractApplicationContext抽象類定義了上下文對(duì)象初始化核心流程,SpringBootBeanFactoryPostProcessor的方式實(shí)現(xiàn)包掃描楞陷、自動(dòng)配置固蛾,將Bean預(yù)先加載成BeanDefinition后并實(shí)例化

  6. 后續(xù)處理
    發(fā)布應(yīng)用已啟動(dòng)事件并且調(diào)用容器中的Runner

一艾凯、設(shè)置應(yīng)用類型

當(dāng)前的web應(yīng)用類型webApplicationType)是在SpringApplication構(gòu)造函數(shù)中設(shè)置的趾诗,設(shè)置的邏輯在WebApplicationType.deduceFromClasspath中:

   if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) 
                           && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
                           && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
       return WebApplicationType.REACTIVE;
   }
   for (String className : SERVLET_INDICATOR_CLASSES) {
       if (!ClassUtils.isPresent(className, null)) {
           return WebApplicationType.NONE;
       }
   }
   return WebApplicationType.SERVLET;

可以看出SpringBoot將應(yīng)用程序分為三種類型:

  1. Reactive
    Spring團(tuán)隊(duì)推出的Reactor編程模型的非阻塞異步Web編程框架WebFlux

  2. Servlet
    基于J2EE Servlet API的編程模型沧竟,運(yùn)行在Servlet容器上

  3. None
    非Web應(yīng)用程序

通過(guò)類路徑中是否存在WebFlux中的DispatcherhandlerSpringMVC中的DispatcherServlet闪水、Servlet球榆、ConfigurableWebApplicationContext來(lái)推斷Web應(yīng)用程序類型

二持钉、準(zhǔn)備應(yīng)用上下文環(huán)境(Environment)

EnvironmentSpringFramework中一個(gè)很重要的接口篱昔,用于存放應(yīng)用程序配置信息

PropertySourceorg.springframework.core.env.PropertySource)是用來(lái)將一個(gè)對(duì)象以鍵值對(duì)的形式表示州刽,Spring將多種來(lái)源的屬性鍵值對(duì)轉(zhuǎn)換成PropertySource來(lái)表示

//SpringApplication的prepareEnvironment方法
    private ConfigurableEnvironment prepareEnvironment(
            SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments) {
        // Create and configure the environment
        ConfigurableEnvironment environment = getOrCreateEnvironment();//創(chuàng)建環(huán)境對(duì)象
        configureEnvironment(environment, applicationArguments.getSourceArgs());//配置環(huán)境對(duì)象;主要是根據(jù)命令行參數(shù)配置profile
        listeners.environmentPrepared(environment);//發(fā)布應(yīng)用環(huán)境已準(zhǔn)備事件
        bindToSpringApplication(environment);//綁定spring.main屬性到SpringApplication對(duì)象中
        if (!this.isCustomEnvironment) {
            environment = new EnvironmentConverter(getClassLoader())
                    .convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());//如果用戶設(shè)置的spring.main.web-application-type和spring推斷的類型不一致辨绊,則使用用戶設(shè)置的類型门坷,創(chuàng)建對(duì)應(yīng)的環(huán)境對(duì)象
        }
        ConfigurationPropertySources.attach(environment);//添加一個(gè)名為configurationProperties的PropertySource
        return environment;
    }

在這一步,SpringApplication做了:

  1. 創(chuàng)建Environment對(duì)象
    getOrCreateEnvironment方法中框冀,會(huì)根據(jù)之前推斷的webApplicationType(web程序類型)創(chuàng)建不同了實(shí)現(xiàn)的Environment對(duì)象

  2. 配置Environment對(duì)象

    1. 應(yīng)用程序如果有命令行參數(shù)明也,則在Environment中添加一個(gè)與這個(gè)命令行參數(shù)相關(guān)的PropertySource
    2. 根據(jù)命令行參數(shù)中spring.profiles.active屬性配置Environment對(duì)象中的activeProfile
  3. 發(fā)布ApplicationEnvironmentPreparedEvent(應(yīng)用環(huán)境已準(zhǔn)備)事件

    SpringApplication發(fā)布完這個(gè)事件后温数,一個(gè)類型為ConfigFileApplicationListener的監(jiān)聽(tīng)器會(huì)監(jiān)聽(tīng)這個(gè)事件撑刺,它會(huì)去讀取用戶設(shè)置的profile文件(讀取profile的詳細(xì)流程在下一步中)

  4. Environment中的spring.main屬性綁定到SpringAppilcation對(duì)象中

    在執(zhí)行到這一步時(shí)够傍,Environment中已經(jīng)包含了用戶設(shè)置的profile文件屬性

  5. 轉(zhuǎn)換Environment對(duì)象的類型
    在上一步中冕屯,如果用戶使用spring.main.web-application-type屬性手動(dòng)設(shè)置了應(yīng)用程序的webApplicationType并且用戶設(shè)置的類型與SpringApplication推斷出來(lái)的不一致安聘,則SpringApplication會(huì)將環(huán)境對(duì)象轉(zhuǎn)換成用戶設(shè)置的webApplicationType相關(guān)的類型

三浴韭、讀取profile

在創(chuàng)建Environment對(duì)象前念颈,SpringAppilcation已經(jīng)將當(dāng)前類路徑j(luò)ar包下所有spring.factories文件中的ApplicationListener加載并實(shí)例化完畢榴芳。

ApplicationListenerSpring Framework中的監(jiān)聽(tīng)器接口翠语,用來(lái)監(jiān)聽(tīng)?wèi)?yīng)用程序發(fā)布的事件

監(jiān)聽(tīng)器列表中有一個(gè)類型為ConfigFileApplicationListener的監(jiān)聽(tīng)器肌括,當(dāng)監(jiān)聽(tīng)到ApplicationEnvironmentPreparedEvent事件時(shí)谍夭,它會(huì)從所有spring.factories中加載EnvironmentPostProcessor(環(huán)境后處理器)并執(zhí)行他們的postProcessEnvironment方法(這個(gè)監(jiān)聽(tīng)器本身也是一個(gè)環(huán)境后處理器紧索,所以它也會(huì)執(zhí)行自身的postProcessEnvironment方法珠漂,在這個(gè)方法中加載了用戶設(shè)置的profile并以PropertySource的形式添加到Environment中)。

ConfigFileApplicationListener最終會(huì)構(gòu)造一個(gè)Loader的內(nèi)部類并調(diào)用Loader.load()方法加載profile荞彼;在Loader的構(gòu)造函數(shù)中鸣皂,會(huì)去加載所有spring.factories中的PropertySourceLoader寞缝,SpringBoot提供了兩個(gè)PropertySourceLoader

  • PropertiesPropertySourceLoader(用來(lái)加載properties荆陆、xml文件)
  • YamlPropertySourceLoader(用來(lái)加載yml慎宾、yaml文件)

Loader.load()加載profile的偽代碼:

  • 配置文件目錄
    如果用戶設(shè)置了spring.config.location屬性(用","分隔開(kāi)表示多個(gè)),則使用這個(gè)屬性值作為配置文件目錄;否則使用默認(rèn)的目錄(classpath:/,classpath:/config/,file:./,file:./config/)和spring.config.additional-location設(shè)置的并集作為配置文件目錄

  • 配置文件名稱
    如果用戶設(shè)置了spring.config.name屬性(用","分隔表示多個(gè))术健,則使用這個(gè)屬性作為配置文件名稱荞估;否則使用application作為配置文件名

  • 文件擴(kuò)展名

//此時(shí)還沒(méi)有加載profile,因此兩個(gè)屬性的值只能通過(guò)命令行參數(shù)讀取到
let profiels = spring.profiles.active和spring.profiles.include設(shè)置的值  
for(profile : profiles){//profiles是一個(gè)雙向隊(duì)列
    for(目錄 : 配置文件目錄集合){
        let 配置文件名集合 = 集合;
        for(文件名 : 配置文件名集合){
            for(loader : propertySourceLoader){
                for(文件擴(kuò)展名 : loader.文件擴(kuò)展名){
                    load(profile,目錄 + 文件名 + "-" + profile + "." + 文件擴(kuò)展名);
                }
            }
        }
    }
}
在load(加載)時(shí)勘伺,如果從當(dāng)前的`profile`中讀取到了`spring.profiles.active`和`spring.profiles.include`屬性飞醉,會(huì)把解析出來(lái)的profile放入profiles中

通過(guò)以目錄 + 文件名 + "-" + profileName + "." + 文件擴(kuò)展名的組合方式加載profile缅帘,并將profilePropertySource的形式添加到Environment中。

profile屬性的優(yōu)先級(jí)問(wèn)題:如果在多個(gè)profile中設(shè)置了同一個(gè)名稱的屬性逗栽,profile屬性生效的規(guī)則是怎樣的彼宠?

  • 同名的profile:根據(jù)文件后綴優(yōu)先級(jí) properties > xml > yml > yaml

  • 被引用的profile:例一個(gè)profile中同時(shí)有spring.profiles.activespring.profiles.include屬性,則active的優(yōu)先級(jí) > include的優(yōu)先級(jí)

  • 默認(rèn)的profile優(yōu)先級(jí)別最低

  • 如果把默認(rèn)的profile當(dāng)做第一級(jí)profile想罕,在第一級(jí)profile中引用的profile(使用spring.profiles.active或者spring.profiles.include引用)當(dāng)做下一級(jí)的profile按价,則下一級(jí)的profile(可能多個(gè))優(yōu)先級(jí)高于前一級(jí)的profile(一個(gè))楼镐,多個(gè)profile整體的優(yōu)先級(jí)為第一級(jí)的profile優(yōu)先級(jí)框产;例:
    application.yml內(nèi)容:
    spring.profiles.active=p1,p2
    spring.profiles.include=p3,p4

    application-p1.yml內(nèi)容:
    spring.profiles.include=p5
    p2 > p1 > p4 > p3 > default 其中p5 > p1秉宿,結(jié)果是p2 > p5 > p1 > p4 > p3 > default

四描睦、創(chuàng)建并配置應(yīng)用上下文對(duì)象

ApplicationContextSpring Framework中最核心的接口忱叭,用來(lái)表示一個(gè)應(yīng)用的上下文韵丑;功能包括事件發(fā)布撵彻、國(guó)際化等千康,同時(shí)它也是一個(gè)BeanFactory

SpringApplication通過(guò)webApplicationType的類型來(lái)創(chuàng)建不同的ApplicationContext值桩,以SERVLET類型的webApplicationType為例奔坟,SpringApplication會(huì)創(chuàng)建類型為AnnotationConfigServletWebServerApplicationContext的上下文對(duì)象咳秉;

SpringApplicationprepareContext方法中對(duì)上下文對(duì)象進(jìn)行預(yù)配置澜建,主要做了

  • 執(zhí)行所有ApplicationContextInitializerinitialize方法
    這些ApplicationContextInitializer是在SpringApplication中的構(gòu)造函數(shù)中加載的(通過(guò)讀取spring.factories加載)
  • 發(fā)布ApplicationContextInitializedEvent(上下文已初始化)事件
  • 發(fā)布ApplicationPreparedEvent(上下文已準(zhǔn)備)事件

五炕舵、刷新應(yīng)用上下文對(duì)象

這里是ApplicationContext真正開(kāi)始初始化容器和創(chuàng)建bean的階段,其中bean的整個(gè)生命周期可以從這一步驟看出來(lái)徊件;Spring Framework中的所有ApplicationContext實(shí)現(xiàn)都直接或間接繼承自AbstracttApplicationContext睹耐,它的refresh方法描述了整個(gè)上下文的初始化邏輯

AnnotationConfigServletWebServerApplicationContext(當(dāng)應(yīng)用的webApplicationType為Servlet時(shí)使用)這個(gè)實(shí)現(xiàn)類為例

AbstractApplicationContext的refresh方法

synchronized (this.startupShutdownMonitor) {
                prepareRefresh();//(1)
                ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();//(2)
                prepareBeanFactory(beanFactory);//(3)
                try {
                    postProcessBeanFactory(beanFactory);//(4)
                    invokeBeanFactoryPostProcessors(beanFactory);//(5)
                    registerBeanPostProcessors(beanFactory);//(6)
                    initMessageSource();//(7)
                    initApplicationEventMulticaster();//(8)
                    onRefresh();//(9)
                    registerListeners();//(10)
                    finishBeanFactoryInitialization(beanFactory);//(11)
                    finishRefresh();//(12)
                }catch (BeansException ex) {
                    //疏橄。。表牢。崔兴。敲茄。堰燎。
                }
                finally {
                    resetCommonCaches();
                }
}
1. 準(zhǔn)備更新上下文時(shí)的預(yù)備工作:
  • 初始化PropertySource
  • 驗(yàn)證Enrivonment中必要的屬性
2. 獲取上下文的內(nèi)部BeanFactory

內(nèi)部BeanFactory的實(shí)現(xiàn)類是DefaultListableBeanFactory

3. 對(duì)BeanFactory做些預(yù)備工作:
  • 設(shè)置BeanFactoryBean類加載器赊淑、Bean表達(dá)式解析器陶缺、屬性編輯器注冊(cè)表
  • 添加類型為ApplicationContextAwareProcessor饱岸、ApplicationListenerDetectorBeanPostProcessor
  • BeanFactory在自動(dòng)裝配時(shí)忽略一些接口類型
  • 注冊(cè)可解析的依賴(自動(dòng)裝配時(shí)碰到這些類型直接注入,包括BeanFactory苫费、ResourceLoaderApplicationEventPublisher荠诬、ApplicationContext
  • BeanFactory中注冊(cè)一些單例對(duì)象柑贞,包括environment钧嘶、systemProperties有决、systemEnvironment
4. 對(duì)BeanFactory進(jìn)行預(yù)處理
  • 添加一個(gè)WebApplicationContextServletContextAwareProcessorBeanPostProcessor
  • 使BeanFactory自動(dòng)裝配時(shí)忽略ServletContextAware接口
  • BeanFactory中注冊(cè)request新荤、session兩種scope
  • 注冊(cè)可解析的依賴(自動(dòng)裝配時(shí)碰到這些類型可以注解注入,包括ServletRequest苛骨、ServletResponseHttpSession俐筋、WebRequest)
5. 執(zhí)行容器中的BeanFactoryPostProcessor執(zhí)行到這時(shí)容器已經(jīng)注冊(cè)了三個(gè)BeanFactoryPostProcessor澄者,分別為
  • SharedMetadataReaderFactoryContextInitializer$CachingMetadataReaderFactoryPostProcessor
    ApplicationContexttInitializer初始化時(shí)注冊(cè)
  • ConfigurationWarningsApplicationContextInitializer#ConfigurationWarningsPostProcessor
    ApplicationContexttInitializer初始化時(shí)注冊(cè)
  • ConfigFileApplicationListener$PropertySourceOrderingPostProcessor
    ApplicationPreparedEvent事件發(fā)布時(shí)由ConfigFileApplicationListener注冊(cè)

BeanDefinitionRegistryPostProcessor是一種特殊的BeanFactoryPostProcessor,可以對(duì)BeanDefinition的注冊(cè)表進(jìn)行預(yù)處理

  1. BeanFactory中找到已注冊(cè)的BeanFactoryPostProcessor抱怔,執(zhí)行其中類型為BeanDefinitionRegistryPostProcessorpostProcessBeanDefinitionRegistry方法

  2. 循環(huán)從BeanFactory中獲取BeanDefinitionRegistryPostProcessor(從BeanDefinition注冊(cè)表中獲取屈留,和上一步的來(lái)源不一樣)灌危;有一個(gè)ConfigurationClassPostProcessorApplicationContext的構(gòu)造函數(shù)中注冊(cè)的)
    ConfigurationClassPostProcessor會(huì)執(zhí)行SpringBoot的自動(dòng)裝配功能勇蝙,將spring.factories中類型為EnableAutoConfiguration的類讀取成BeanDefinition并過(guò)濾掉不滿足條件的然后注冊(cè)到BeanFactory中味混。詳細(xì)步驟在下一章

    這一步驟會(huì)不斷從BeanFactory中獲取沒(méi)有執(zhí)行的BeanDefinitionRegistryPostProcessor并執(zhí)行(可能用戶會(huì)里面注冊(cè)同類型的處理器)直到?jīng)]有找到新的BeanDefinitionRegistryPostProcessor

    包掃描翁锡、自動(dòng)裝配的功能都在ConfigurationClassPostProcessor中完成,執(zhí)行完這一步后角溃,所有Bean都會(huì)加載成BeanDefinition放入容器中

  3. 執(zhí)行他們的postProcessBeanFactory方法對(duì)BeanFactory進(jìn)行后處理

6. 注冊(cè)BeanPostProcessor

BeanPostProcessor:Bean生命周期的鉤子开镣,允許用戶對(duì)實(shí)例化后的Bean進(jìn)行操作

  1. 從BeanFactory中獲取所有BeanPostProcessor

  2. BeanFactory中注冊(cè)一個(gè)類型為BeanPostProcessorChecker的BeanPostProcessor

  3. 將所有BeanPostProcessor按照實(shí)現(xiàn)了PriorityOrdered邪财、Ordered树埠、沒(méi)有實(shí)現(xiàn)排序接口的順序注冊(cè)所有BeanPostProcessorBeanFactory

  4. BeanFactory中注冊(cè)一個(gè)類型為ApplicationListenerDetectorBeanPostProcessor

7. 初始化MessageSource(國(guó)際化相關(guān))//忽略
8. 初始化容器事件廣播器(用來(lái)發(fā)布事件)
  • 構(gòu)造了一個(gè)SimpleApplicationEventMulticaster當(dāng)成默認(rèn)的事件廣播器
9. 初始化一些特殊的Bean,主要做了:
  1. 初始化ThemeSource(跟國(guó)際化相關(guān)的接口)
  2. 創(chuàng)建WebServer
10. 將所有監(jiān)聽(tīng)器注冊(cè)到前兩步創(chuàng)建的事件廣播器中
11. 結(jié)束B(niǎo)eanFactory的初始化工作(這一步主要用來(lái)將所有的單例BeanDefinition實(shí)例化)
  1. BeanFactory中獲取所有的BeanDefinitionbeanName并遍歷

  2. 對(duì)Bean執(zhí)行所有已注冊(cè)的InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation方法(如果這個(gè)方法返回了一個(gè)Bean,Spring不會(huì)對(duì)這個(gè)Bean的屬性進(jìn)行注入,并且這個(gè)Bean的生命周期也會(huì)缺少幾個(gè)步驟)
    PS:只要其中有一個(gè)方法的返回值不為null,則會(huì)立即返回這個(gè)Bean绊袋,這個(gè)Bean的生命周期和正常的Bean不同(Spring對(duì)這個(gè)類型的BeanPostProcessor的注釋是讓它有機(jī)會(huì)能返回一個(gè)代理對(duì)象)

  3. 實(shí)例化bean

  4. 對(duì)Bean執(zhí)行所有MergedBeanDefinitionPostProcessor.prostProcessMergedBeanDefinition(用來(lái)修改BeanDefinition的信息)

  5. 對(duì)Bean屬性進(jìn)行填充(還有利用BeanPostProcessor對(duì)特殊Bean創(chuàng)建代理等暫時(shí)不討論)

    1. 獲取BeanFactory中所有InstantiationAwareBeanPostProcessor,對(duì)Bean執(zhí)行postProcessAfterInstantiation方法(通常展姐,這個(gè)方法應(yīng)該返回true圾笨,如果返回false擂达,后續(xù)的postProcessAfterInstantiation方法就不會(huì)執(zhí)行了)
    2. 同上板鬓,獲取所有InstantiationAwareBeanPostProcessor穗熬,對(duì)每一個(gè)InstantiationAwareBeanPostProcessor分兩次調(diào)用
      1.postProcessProperties,如果返回null,則繼續(xù)調(diào)用下一步
      1. postProcessPropertyValues(返回的PropertyValues是最終使用的PropertyValues唤蔗。如果這一步返回null,則不會(huì)執(zhí)行后面的InstantiationAwareBeanPostProcessor
      2. 如果上一步返回的PropertyValues有屬性妓柜,則將屬性應(yīng)用到bean
  6. 對(duì)實(shí)現(xiàn)了BeanNameAware棍掐、BeanClassLoaderAware作煌、BeanFactoryAware的接口進(jìn)行接口調(diào)用

  7. 對(duì)Bean執(zhí)行BeanPostProcessor.postProcessBeforeInitialization方法

  8. 對(duì)實(shí)現(xiàn)了InitializingBeanBean調(diào)用接口方法,然后調(diào)用init-method(可以是@PostConstruct標(biāo)注的方法)

  9. 對(duì)Bean執(zhí)行PostProcessor.postProcessAfterInitialization方法

  10. 如果Bean是一個(gè)SmartInitializingSingleton,則調(diào)用BeanafterSingletonsInstantiated方法

  • 對(duì)于EnvironmentAware奏寨、ResourceLoaderAware病瞳、ApplicationEventPublisherAware套菜、MessageSourceAwareAppilcationContextAware等接口嚎于,是使用ApplicationContextAwareProcessor這個(gè)BeanPostProcessorpostProcessBeforeInitialization方法)實(shí)現(xiàn)調(diào)用的
  • 步驟2中于购,如果postProcessBeforeInstantiation返回了一個(gè)bean肋僧,則立馬會(huì)對(duì)bean執(zhí)行步驟8的PosttProcessor.postProcessAfterInitialization方法
12.afterRefresh(上下文刷新完畢)
  1. 初始LifecycleProcessor(生命周期處理器),向BeanFactory注冊(cè)一個(gè)DefaultLifecycleProcessor
  2. 調(diào)用LifecycleProcessoronrefresh方法(找到所有已注冊(cè)的SmartLifecycle,根據(jù)isRunningisAutoStartup的條件判斷辫诅,執(zhí)行SmartLifecyclestart方法)
  3. ServletWebServerApplicationContetxt中炕矮,啟動(dòng)了WebServer并發(fā)布了ServletWebServerInitializedEvent事件
總結(jié):
Spring容器中單例對(duì)象的生命周期
  1. 使用BeanFactoryPostProcessor對(duì)BeanFactory進(jìn)行預(yù)處理

  2. 對(duì)未實(shí)例化的Bean調(diào)用InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation方法

  3. 實(shí)例化Bean(此時(shí)會(huì)調(diào)用Bean構(gòu)造函數(shù))

  4. 對(duì)Bean調(diào)用MergedBeanDefinitionPostProcessor.prostProcessMergedBeanDefinition可用來(lái)修改BeanDefinition信息

  5. 對(duì)Bean調(diào)用InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation方法

  6. 對(duì)Bean調(diào)用InstantiationAwareBeanPostProcessor.postProcessProperties可用來(lái)修改Bean的屬性配置

  7. 對(duì)Bean調(diào)用InstantiationAwareBeanPostProcessor.postProcessPropertyValues可用來(lái)修改Bean的屬性配置

  8. 對(duì)實(shí)現(xiàn)了BeanNameAware肤视、BeanClassLoaderAware、BeanFactoryAwareBean進(jìn)行接口調(diào)用注入屬性

  9. 對(duì)Bean調(diào)用BeanPostProcessor.postProcessBeforeInitialization可對(duì)實(shí)例化的Bean進(jìn)行操作

  10. 對(duì)實(shí)現(xiàn)了InitializingBeanBean調(diào)用接口方法,然后有初始化方法(可以是@PostConstruct標(biāo)注的方法)的話調(diào)用初始化方法

  11. 對(duì)Bean執(zhí)行PostProcessor.postProcessAfterInitialization方法可對(duì)實(shí)例化的Bean進(jìn)行操作

  12. 如果Bean實(shí)現(xiàn)了SmartInitializingSingleton接口,則調(diào)用Bean的afterSingletonsInstantiated方法

SpringApplicationrefresh方法調(diào)用結(jié)束后困后,在JVM上注冊(cè)了一個(gè)shutdownHook锯仪,JVM正常關(guān)閉時(shí)會(huì)調(diào)用,其中做了一些資源清理和調(diào)用Beanclose的方法工作(單例Bean生命周期的一部分)

六救鲤、后續(xù)處理

  • 發(fā)布應(yīng)用程序已啟動(dòng)(ApplicationStartedEvent)事件
  • BeanFactory中獲取所有ApplicationRunnerCommandLineRunner并調(diào)用他們的run方法
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市丹锹,隨后出現(xiàn)的幾起案子楣黍,更是在濱河造成了極大的恐慌租漂,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,599評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件业筏,死亡現(xiàn)場(chǎng)離奇詭異蒜胖,居然都是意外死亡翠勉,警方通過(guò)查閱死者的電腦和手機(jī)对碌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,629評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門怀读,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)菜枷,“玉大人,你說(shuō)我怎么就攤上這事蚊锹∧道ィ” “怎么了丢烘?”我有些...
    開(kāi)封第一講書人閱讀 158,084評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)垄开。 經(jīng)常有香客問(wèn)我讯泣,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 56,708評(píng)論 1 284
  • 正文 為了忘掉前任姜贡,我火速辦了婚禮楼咳,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘缚柏。我一直安慰自己轨域,他們只是感情好干发,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,813評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布冀续。 她就那樣靜靜地躺著沥阳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪桂敛。 梳的紋絲不亂的頭發(fā)上术唬,一...
    開(kāi)封第一講書人閱讀 50,021評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音借浊,去河邊找鬼蚂斤。 笑死曙蒸,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的兼吓。 我是一名探鬼主播趋艘,決...
    沈念sama閱讀 39,120評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼显拳,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼搓萧!你這毒婦竟也來(lái)了瘸洛?” 一聲冷哼從身側(cè)響起那伐,我...
    開(kāi)封第一講書人閱讀 37,866評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤罕邀,失蹤者是張志新(化名)和其女友劉穎诉探,沒(méi)想到半個(gè)月后肾胯,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體敬肚,經(jīng)...
    沈念sama閱讀 44,308評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡帘皿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,633評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了曹动。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,768評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡兔港,死狀恐怖衫樊,靈堂內(nèi)的尸體忽然破棺而出科侈,到底是詐尸還是另有隱情臀栈,我是刑警寧澤,帶...
    沈念sama閱讀 34,461評(píng)論 4 333
  • 正文 年R本政府宣布崭闲,位于F島的核電站威蕉,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏虑粥。R本人自食惡果不足惜娩贷,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,094評(píng)論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望储笑。 院中可真熱鬧突倍,春花似錦焊虏、人聲如沸诵闭。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,850評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至驱富,卻和暖如春褐鸥,著一層夾襖步出監(jiān)牢的瞬間叫榕,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,082評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工荞下, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人会宪。 一個(gè)月前我還...
    沈念sama閱讀 46,571評(píng)論 2 362
  • 正文 我出身青樓塞帐,卻偏偏與公主長(zhǎng)得像葵姥,于是被迫代替她去往敵國(guó)和親句携。 傳聞我的和親對(duì)象是個(gè)殘疾皇子削咆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,666評(píng)論 2 350

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