javascript
学习Spring Boot:(二)启动原理
前言
主要了解前面的程序入口 @@SpringBootApplication 這個注解的結構。
正文
參考《SpringBoot揭秘 快速構建微服務體系》第三章的學習,總結下。
SpringBootApplication背后的秘密
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = {@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication { ... }雖然定義使用了多個Annotation進行了原信息標注,但實際上重要的只有三個Annotation:
- @Configuration(@SpringBootConfiguration點開查看發(fā)現(xiàn)里面還是應用了@Configuration)
- @EnableAutoConfiguration
- @ComponentScan
所以,如果我們使用如下的SpringBoot啟動類,整個SpringBoot應用依然可以與之前的啟動類功能對等:
@Configuration @EnableAutoConfiguration @ComponentScan public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);} }但每次都寫三個Annotation顯然過于繁瑣,所以寫一個@SpringBoot-Application這樣的一站式復合Annotation顯然更方便些。
@Configuration創(chuàng)世紀
這里的@Configuration對我們來說并不陌生,它就是JavaConfig形式的Spring IoC容器的配置類使用的那個@Configuration,既然SpringBoot應用骨子里就是一個Spring應用,那么,自然也需要加載某個IoC容器的配置,而SpringBoot社區(qū)推薦使用基于JavaConfig的配置形式,所以,很明顯,這里的啟動類標注了@Configuration之后,本身其實也是一個IoC容器的配置類!
很多SpringBoot的代碼示例都喜歡在啟動類上直接標注@Configuration或者@SpringBootApplication,對于初接觸SpringBoot的開發(fā)者來說,其實這種做法不便于理解,如果我們將上面的SpringBoot啟動類拆分為兩個獨立的Java類,整個形勢就明朗了:
所以,啟動類DemoApplication其實就是一個標準的Standalone類型Java程序的main函數(shù)啟動類,沒有什么特殊的。
而@Configuration標注的DemoConfiguration定義其實也是一個普通的JavaConfig形式的IoC容器配置類,沒啥新東西,全是Spring框架里的概念!
不要被這個長篇大論弄模糊了,這個其實在以前學習Spring中也有這些注解,Spring容器中為了簡化XMl配置,允許使用JavaConfig注冊一個Bean。就是使用的是@Configuration,每個擁有注解@Bean的函數(shù)的返回值,都將會在SPring啟動時候注冊到容器中,可以使用自動裝配,如下一個JavaConfig的注冊Bean:
@Configuration public class Configs {@Value("classpath:data.json")protected File configFile;@Beanpublic PersonCfg readServerConfig() throws IOException {return new ObjectMapper().readValue(configFile, PersonCfg.class);}@EnableAutoConfiguration的功效
@EnableAutoConfiguration其實也沒啥“創(chuàng)意”,各位是否還記得Spring框架提供的各種名字為@Enable開頭的Annotation定義?比如@EnableScheduling、@EnableCaching、@EnableMBeanExport等,@EnableAutoConfiguration的理念和“做事方式”其實一脈相承,簡單概括一下就是,借助@Import的支持,收集和注冊特定場景相關的bean定義:
* @Enable Scheduling是通過@Import將Spring調(diào)度框架相關的bean定義都加載到IoC容器。
* @Enable M Bean Export是通過@Import將JMX相關的bean定義加載到IoC容器。
而@EnableAutoConfiguration也是借助@Import的幫助,將所有符合自動配置條件的bean定義加載到IoC容器,僅此而已!
@EnableAutoConfiguration作為一個復合Annotation,其自身定義關鍵信息如下:
其中,最關鍵的要屬@Import(EnableAutoConfigurationImportSelector.class),借 助EnableAutoConfigurationImportSelector, @EnableAutoConfiguration可以幫助SpringBoot應用將所有符合條件的@Configuration配置都加載到當前SpringBoot創(chuàng)建并使用的IoC容器,就跟一只“八爪魚”一樣。
借助于Spring框架原有的一個工具類:SpringFactoriesLoader的支持,@EnableAutoConfiguration可以“智能”地自動配置功效才得以大功告成!
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-zrSW4kJm-1637076750895)(https://ws1.sinaimg.cn/large/ece1c17dgy1fnoe3ayl8oj20qd0pf0vs.jpg)]
自動配置幕后英雄:SpringFactoriesLoader詳解
SpringFactoriesLoader屬于Spring框架私有的一種擴展方案,其主要功能就是從指定的配置文件META-INF/spring.factories加載配置。
public abstract class SpringFactoriesLoader {//...public static <T> List<T> loadFactories(Class<T> factoryClass, ClassLoader classLoader) {...}public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {....} }配合@EnableAutoConfiguration使用的話,它更多是提供一種配置查找的功能支持,即根據(jù)@EnableAutoConfiguration的完整類名org.springframework.boot.autoconfigure.EnableAutoConfiguration作為查找的Key,獲取對應的一組@Configuration類:
# PropertySource Loaders org.springframework.boot.env.PropertySourceLoader=\ org.springframework.boot.env.PropertiesPropertySourceLoader,\ org.springframework.boot.env.YamlPropertySourceLoader# Run Listeners org.springframework.boot.SpringApplicationRunListener=\ org.springframework.boot.context.event.EventPublishingRunListener# Application Context Initializers org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\ org.springframework.boot.context.ContextIdApplicationContextInitializer,\ org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\ org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer# Application Listeners org.springframework.context.ApplicationListener=\ org.springframework.boot.ClearCachesApplicationListener,\ org.springframework.boot.builder.ParentContextCloserApplicationListener,\ org.springframework.boot.context.FileEncodingApplicationListener,\ org.springframework.boot.context.config.AnsiOutputApplicationListener,\ org.springframework.boot.context.config.ConfigFileApplicationListener,\ org.springframework.boot.context.config.DelegatingApplicationListener,\ org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,\ org.springframework.boot.logging.ClasspathLoggingApplicationListener,\ org.springframework.boot.logging.LoggingApplicationListener# Environment Post Processors org.springframework.boot.env.EnvironmentPostProcessor=\ org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\ org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor# Failure Analyzers org.springframework.boot.diagnostics.FailureAnalyzer=\ org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer# FailureAnalysisReporters org.springframework.boot.diagnostics.FailureAnalysisReporter=\ org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter以上是從SpringBoot的autoconfigure依賴包中的META-INF/spring.factories配置文件中摘錄的一段內(nèi)容,可以很好地說明問題。
以,@EnableAutoConfiguration自動配置的魔法其實就變成了:從classpath中搜尋所有META-INF/spring.factories配置文件,并將其中org.spring-framework.boot.autoconfigure.EnableAutoConfiguration對應的配置項通過反射(Java Reflection)實例化為對應的標注了@Configuration的JavaConfig形式的IoC容器配置類,然后匯總為一個并加載到IoC容器。
可有可無的@Configuration
@Component Scan的功能其實就是自動掃描并加載符合條件的組件或bean定義,最終將這些bean定義加載到容器中。加載bean定義到Spring的IoC容器,我們可以手工單個注冊,不一定非要通過批量的自動掃描完成,所以說@Component Scan是可有可無的。
深入探索SpringApplication執(zhí)行流程
SpringApplication的run方法的實現(xiàn)是我們本次旅程的主要線路, 該方法的主要流程大體可以歸納如下:
- 根據(jù)classpath里面是否存在某個特征類(org.springframework.web.context.ConfigurableWebApplicationContext)來決定是否應該創(chuàng)建一個為Web應用使用的ApplicationContext類型,還是應該創(chuàng)建一個標準Standalone應用使用的ApplicationContext類型。
- 使用SpringFactoriesLoader在應用的classpath中查找并加載所有可用的ApplicationContextInitializer。
- 使用SpringFactoriesLoader在應用的classpath中查找并加載所有可用的ApplicationListener。
- 推斷并設置main方法的定義類。
至此,一個完整的SpringBoot應用啟動完畢!
整個過程看起來冗長無比,但其實很多都是一些事件通知的擴展點,如果我們將這些邏輯暫時忽略,那么,其實整個SpringBoot應用啟動的邏輯就可以壓縮到極其精簡的幾步。
參考文章
- 《SpringBoot揭秘 快速構建微服務體系》 第三章
總結
以上是生活随笔為你收集整理的学习Spring Boot:(二)启动原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 嵌入式笔录(6)单管收音机电路分析
- 下一篇: 工业用微型计算机(12)-指令系统(7)