spring boot 源碼分析


  說明:spring boot版本 2.0.6.RELEASE

思緒

首先,大家認識spring boot是從@SpringBootApplication注解和org.springframework.boot.SpringApplication.run(Class<?>, String...)開始的,那么我們就從這兩個方向入手一探究竟。

@SpringBootApplication注解

先來看下@SpringBootApplication的申明,如下圖:

核心也就是@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan這三個注解的組合。

@SpringBootConfiguration如下,即標明被@SpringBootApplication注解標注的類本身也是spring的java config類。

@ComponentScan,配置自動掃描功能,等同xml配置的<context:component-scan>。可以指定basePackages或者basePackageClasses標明掃描的根路徑,如果不設置的話默認掃描@ComponentScan注解所在類的同級類和同級目錄下的所有類,也就是@SpringBootApplication所在的類,所以一般spring boot項目的入口類會放在頂層目錄中,這樣就可以自動掃描到項目中所有的spring配置類,該注解的處理類為org.springframework.context.annotation.ComponentScanAnnotationParser.parse(AnnotationAttributes, String),從ApplicationContext中refresh的invokeBeanFactoryPostProcessors調用過來的,調用棧如下圖所示:

 @EnableAutoConfiguration,自動配置類,是簡化spring配置的核心,spring一貫的風格凡是enable開頭的注解都會配備一個@Import注解來引入一個ImportSelector。這里的@Import如下圖所示:

掃盲:@Import注解作用是將values配置的class加入springIOC容器中:

如果是@Configuration的配置類,則將對應的java config產生的bean納入spring管理;

如果是普通java類,則將該類實例化並納入spring管理;

重點看下org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.selectImports(AnnotationMetadata)方法,返回一個string數組,內容為需要加載的類限定名。

核心是通過spring的FactoriesLoader機制加載以EnableAutoConfiguration注解全限定類名為key的class。

核心在org.springframework.core.io.support.SpringFactoriesLoader.loadSpringFactories(ClassLoader)方法中,如下圖所示,其實就是在classpath下查找所有

META-INF/spring.factories文件中以EnableAutoConfiguration.getName為key的string列表。

 

下圖就是其中一個示例:

spring.factories相關內容如下:

以直觀的web容器自動配置為例:

其中的ServletWebServerFactoryAutoConfiguration和ReactiveWebServerFactoryAutoConfiguration即為根據ConditionalOnWebApplication應用類型來加載對應的webServerFactory,classpath下的自動配置webServer:

備注:ServletWebServer和ReactiveWebServer是兩個路子,根據WebApplicationType走不同的路。

拿ReactiveWebServerFactoryAutoConfiguration來說,如下圖所示,@Import了ConditionalOnWebApplication.Type.REACTIVE應用類型可能用到的WebServerFactory。

內部再根據對應條件創建對應的WebServerFactory。

最終org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.getWebServerFactory()以及

org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.getWebServerFactory()從BeanFactory獲取對應的WebServerFactory

 串起來的話是在org.springframework.context.support.AbstractApplicationContext.refresh()中的onRefresh()[子類]的createWebServer創建server,finishRefresh()[子類]啟動server。

 好了,到這里spring boot的@SpringBootApplication注解就分析完了。

SpringApplication.run分析

方法入口先創建SpringApplication對象,然后調用實例run方法,如下圖。

先看看構造方法都做了些什么:

1. 推斷webApplicationType

2. 通過SpringFactoriesLoader機制獲取並創建ApplicationContextInitializer和ApplicationListener

3. 推斷應用主class(mainApplicationClass)

這些是用於擴展用的,在整個啟動過程中插入對應的擴展點,具體邏輯要看實現這些接口的具體類里面的邏輯。

 

我們先來看主線流程,分析源碼要先把主線流程邏輯拉通,再看各個點的邏輯,由面及點,這樣才不會讓自己陷入其中,不明所以。

如下圖所示,主線其實就是創建了一個context,prepareContext以及refresh該context。

創建context

根據之前構造方法中推動出的應用類型創建對應的context,如下圖所示。

我們拿reactive類型來說,對應的context為org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext

繼承關系如下:

創建沒什么,就這么多,重點是下面講的prepareContext

prepareContext

里面重點是加載beanDefinitions,而原來spring框架里面是在org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory()創建完beanFactory后loadBeanDefinitions,詳見下面refreshContext的分析。

 

refreshContext

最終調用的是org.springframework.context.support.AbstractApplicationContext.refresh()這個方法,了解spring的人應該很清楚這個方法,我之前的spring啟動過程源碼分析文章也講得很清楚了。方法內容如下:

重點看下obtainFreshBeanFactory方法,如下圖所示:

里面重點是refreshBeanFactory方法,我們先看下繼承關系:

而spring原有的context繼承自上面那個類,如下圖所示:

所以refreshBeanFactory在以前spring本身的代碼中,調用的是org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory()方法,如下圖所示,先銷毀再創建新的beanfactory,同時加載beanDefinitions,當然,第一創建beanFactory也是在這里。其實從類名很清楚就可以看出,這個基類是支持動態刷新context的:

而spring boot繼承的基類只是setSerializationId,如下圖:

spring boot創建beanFactory是在org.springframework.context.support.GenericApplicationContext.GenericApplicationContext()構造方法中。

至此,spring boot 創建context已經完成,在子類org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.onRefresh()方法中創建webServer,

在finishRefresh中啟動webServer:

子類重寫的這兩個方法在父類org.springframework.context.support.AbstractApplicationContext.refresh()方法中調用的,有沒有get到?這下都串起來了吧。

完結


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM