一 main方法作為程序的入口,執行SpringApplication.run(),傳入參數是啟動類的class對象@SpringBootApplication注解
二 run中首先new SpringApplication對象,然后調用該對象的run方法,返回是一個ConfigurableApplicationContext對象。
三 這里我們先看new SpringApplication的時候會進行什么操作,run方法隨后在看,這段代碼中的每一步依次來說:
1.使用了Assert.notNull來判斷空值是一個良好的習慣,Assert類來自core的org.springframework.util包下,該包提供了很多工具類,之后會單獨有一篇介紹 spring提供給我們好用的工具類的文章。
2.其中會deduceFromClasspath(deduce意為“推斷”)應用類型是servlet還是reactive
classPath中這三個最少有一個
並且這兩個全都有才是一個web應用
3.getSpringFactoriesInstance(ApplicationContextInitiliazer.class)方法從spring-boot包下的"META-INF/spring.factories"路徑加載ClassLoader
該文件:
這種方式更容易看懂共有八個接口分別對應多個實現類:
其中只取key為ApplicationContextInitializer的value返回,該value是個List<String>,是實現了ApplicationContextInitializer接口的實現類名稱,以“,”分隔
然后將這些類進行加載,這些類指的是:
之后同樣的方式加載ApplicationListener接口的實現類:
4.判定主程序是哪個類
通過遍歷棧信息,找到調用main方法的類型,將其加載,賦值給變量mainApplicationClass
四 SpringApplication的run方法
其中重要的邏輯都用黃色框圈了出來:
1.加載所有的監聽器,和上述一樣,加載指定好的類都是根據spring.factories中的對應的監聽器,加載EventPublishingRunListener,之后調用該類的starting:
之后調用該類的starting方法,對之前加載的所有ApplicationListener根據事件類型進行廣播事件(multicastEvent):
2.准備容器環境,會依據之前推斷(deduce)的應用類型返回對應的環境對象:
之后由監聽器執行enviromentPrepared方法,其中需要注意的是會有一個監聽器叫:ConfigFileApplicationListener,該接口的實現類會實際加載yml或.properties的配置文件:
隨后在執行ConfigFileApplicationLitener的postProcessEnviroment方法時,會加載factories的PropertySourceLoader對應的實現類:
來加載yml或.properties中的配置,至此,容器環境配置完成。
3.創建容器上下文createApplicationContext(),也是依據之前的應用類型推斷結果:
之后准備容器上下文:
首先將創建的context中的enviroment全部替換為springApplication中剛剛創建的enviroment,然后向context中注冊beanfactory:
然后用當前context作為參數,調用springApplication中所有的intilizer實現類執行,intilize方法,其中重點關注COnfigurationWaringsApplicationContextInitializer類的該方法:
所有的listener執行contetxPrepared方法,之后向beanfacotry中注冊兩個參數,之后是load方法:
創建了一個beanDefinitionLoader對象,該對象最主要支持了xml加載和annotated加載方式,加載所有source中的對象,這里只有一個主類,被@Component注解(注解繼承),將其注入到beanfactory中的beanDefinitionMap中
在refreshContext中會加載所有的bean到beanFactory中:
至此,就將所有的bean由容器來管理。