學(xué)習(xí)整理摘自
http://www.yund.tech/zdetail.html?type=1&id=2b2a032bd98dfeb5e4113ef6624722d2

springboot啟動原理

先看啟動類注解:SpringBootApplication?
@SpringBootApplication =
@Configuration(SpringBootConfiguration)+
@EnableAutoConfiguration+
@ComponentScan。
@Configuration
@Configuration及@bean兩個注解可以創(chuàng)建一個簡單的spring的配置類,用來替代xml的配置文件


@Configuration的注解類標(biāo)識這個類可以使用Spring IoC容器作為bean定義的來源。
@Bean注解告訴Spring,一個帶有@Bean的注解方法將返回一個對象,該對象應(yīng)該被注冊為在Spring應(yīng)用程序上下文中的bean。

@ComponentScan
功能是自動掃描符合加載條件的組件,比如(@Component)或者bean定義,最終將這些bean定義加載到ioc容器中
spring會默認(rèn)從聲明@componentScan的類的package包下開始掃面,所以springboot的啟動類最好放在根目錄下,因為默認(rèn)不指定basePackages
@EnableAutoConfiguration
借助@import的支持,收集和注冊特定場景相關(guān)的bean定義
類似EnableAutoScheduling是通過@import將spring調(diào)度框架相關(guān)的bean定義加載到ioc容器
類似EnableMBeanExport是通過@import將JMX相關(guān)的bean加載到IOC容器中
而@EnableAutoConfiguration 借助@Import(AutoConfigurationImportSelector.class)將符合自動裝配的bean加載到ioc容器中。也會根據(jù)類路徑中的jar依賴為項目自動裝配;比如spring-boot-starter-web會自動添加tomcat和springmvc進行配置
借助于Spring框架原有的一個工具類:SpringFactoriesLoader(下面詳解)的支持@EnableAutoConfiguration可以智能的自動配置功效才得以大功告成!





每個配置文件一般都有以下的條件注解:
@ConditionalOnClass : classpath中存在該類時起效
@ConditionalOnMissingClass : classpath中不存在該類時起效
@ConditionalOnBean : DI容器中存在該類型Bean時起效
@ConditionalOnMissingBean : DI容器中不存在該類型Bean時起效
@ConditionalOnSingleCandidate : DI容器中該類型Bean只有一個或@Primary的只有一個時起效
@ConditionalOnExpression : SpEL表達式結(jié)果為true時
@ConditionalOnProperty : 參數(shù)設(shè)置或者值一致時起效
@ConditionalOnResource : 指定的文件存在時起效
@ConditionalOnJndi : 指定的JNDI存在時起效
@ConditionalOnJava : 指定的Java版本存在時起效
@ConditionalOnWebApplication : Web應(yīng)用環(huán)境下起效
@ConditionalOnNotWebApplication : 非Web應(yīng)用環(huán)境下起效
SpringFactoriesLoader做法:
主要功能是從指定的配置文件中spring.factories加載配置
SpringFactoriesLoader是一個抽象類,類中定義的靜態(tài)屬性定義了其加載資源的路徑public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories",此外還有三個靜態(tài)方法:
loadFactories:加載指定的factoryClass并進行實例化。
loadFactoryNames:加載指定的factoryClass的名稱集合。
instantiateFactory:對指定的factoryClass進行實例化。

流程:先獲取類加載器,然后調(diào)用loadFactoryNames方法獲取所有的指定資源的名稱集合,接著調(diào)用instantiateFactory方法實例化這些資源類并將其添加到result集合中。
總結(jié): @EnableAutoConfiguration 自動配置就是從classpath中搜尋所有的META-INF/spring.factories配置文件,并將org.springframework.boot.autoconfigure.EnableutoConfiguration對應(yīng)的配置通過反射實例化為對應(yīng)了@Configuration的javaConfig形式的ioc容器類,然后加載到ioc容器中
講完注解接下來講run

一.首先實例一個SpringApplication然后執(zhí)行run()
對于上下文的解釋:
上下文,上下文代表了程序當(dāng)下所運行的環(huán)境,聯(lián)系你整個app的生命周期與資源調(diào)用,是程序可以訪問到的所有資源的總和,資源可以是一個變量,也可以是一個對象的引用。-- 出自知乎
要做4件事情;
1.是否創(chuàng)建一個web類型的ApplicationContext通過deduceWebApplicationType()(主要是看dispatcherHandler和dispatcherServlet能不能被加載)
2.運用springFactoriesLoader在應(yīng)用的classpath中加載所有可用的ApplicationContextInitializer
3.同樣適用springFactoriesLoader加載classpath所有可用的ApplicationListener。將2.3步中獲取的META-INF/spring.factories中的屬性加載到springFactoriesLoader的cache中
4.推斷并設(shè)置main方法的定義類
二.run()主要做了以下的工作:

主要流程:獲取監(jiān)聽器 > 構(gòu)造應(yīng)用上下文環(huán)境 > 初始化應(yīng)用上下文 > 刷新應(yīng)用上下文前的準(zhǔn)備工作 > 刷新應(yīng)用上下文(做了ioc容器初始化過程) > 刷新后的拓展接口?
1.獲取監(jiān)聽器

主要通過getspringFactoriesInstance方法將Application初始化時候加載的監(jiān)聽器實例化,生成運行時監(jiān)聽器EventPublishingRunListener,然后啟動監(jiān)聽器listener.starting(https://www.cnblogs.com/youzhibing/p/9603119.html? - 摘自)
2.構(gòu)造上下文環(huán)境

getOrCreateEnvironment:創(chuàng)建一個環(huán)境,判斷webapplicationType是個什么玩意,如果是webApplicationType.SERVLET 那就創(chuàng)建一個 StandardServletEnvironment
Configuration():重排,移除應(yīng)用環(huán)境中的PropertySource以及通過spring.profiles.avtive屬性,在配置文件的處理期間進行其他的配置文件的激活,分別通過configurePropertySources()及configureProfiles()
listeners.environmentPrepared() :觸發(fā)監(jiān)聽器,內(nèi)部方法與listener.starting的實現(xiàn)一致(沒有理解暫時不寫)
bindToSpringApplication(environment) :將環(huán)境信息environment綁定到SpringApplication
總結(jié):具體做了加載外部資源到environment中,包括命令行參數(shù),serveltConfigInitParams,application.yml(.properties),初始化日志系統(tǒng)
3.初始上下文
之前有一個好玩的是打印banner,可以重新修改下自己玩


總結(jié):通過webApplicationType來獲取對應(yīng)的上下文,然后通過反射方式進行實例化(學(xué)習(xí)https://www.cnblogs.com/youzhibing/p/9686969.html)
什么是BeanDefinition:
Spring容器里通過BeanDefinition對象來表示Bean,BeanDefinition描述了Bean的配置信息;根據(jù)BeanDefinition實例化bean,并放到bean緩存中。
spring bean配置方式:
有三種:基于XML的配置方式 、基于注解的配置方式和基于Java類的配置方式。
基于XML,這個我們都很熟,類似:<bean id="xx" class="xxx" />
基于注解,這個我們也用的比較多,入@Component、@Service、@Controller等
基于java類,spring的推薦配置方式,@Configuration配合@Bean
4.刷新應(yīng)用上下文前的準(zhǔn)備工作
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
將springApplication中的部分屬性應(yīng)用到上下文,springApplication中的environment,initializers,listener應(yīng)用到spring上下文中

context.setEnvironment(environment):
將context中的environment替換成SpringApplication中創(chuàng)建的environment
postProcessApplicationContext(context);
由于當(dāng)前SpringApplication實例的屬性:beanNameGenerator和resourceLoader都為null,所以此方法目前相當(dāng)于什么也沒做。此方法可能是我們定制SpringApplication所用。
applyInitializers(context);
將SpringApplication中的initializers應(yīng)用到context中
5.刷新上下文(*挺多的)

詳細(xì)的refresh()流程:兩個重點的一個是obtainFefeshBeanFactory 另一個是?finishBeanFactoryInitialization()
(重點)obtainFefeshBeanFactory()? 這里面初始化了ioc并將bean注冊到容器中


首先了解下ioc初始化過程:
1.ioc :?DefaultListableBeanFactory beanFactory = createBeanFactory();
1.Resource定位過程:指的是beanDefinition的資源定位,由ResourceLoader通過統(tǒng)一的Resource接口完成 > 通過getResourceByPath獲取resource的定位
2.BeanDefination的載入:把用戶定義好的bean表示成ioc容器內(nèi)部的數(shù)據(jù)結(jié)構(gòu),這個容器內(nèi)w2部的數(shù)據(jù)結(jié)構(gòu)就是BeanDefinition > 通過loadBeanDefinitions(beanFactory)實現(xiàn)
3.向ioc容器注冊beanDefinition:通過RegisterBeanDefinitions () 中的processBeanDefinition()? 將 xml中的bean 轉(zhuǎn)成 beanDefination 并加載容器中
....


....
(重點)finishBeanFactoryInitialization() :負(fù)責(zé)初始化所有singleton bean


進到getbean繼續(xù)往下看doGetBean源碼





6.刷新后的拓展接口?

spring 三級緩存
https://blog.csdn.net/qq_44836294/article/details/107795639




讀取spring的配置文件

zk

https://www.cnblogs.com/lsgspace/p/10508180.html
