日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

学习Spring Boot:(二)启动原理

發布時間:2025/3/12 javascript 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 学习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點開查看發現里面還是應用了@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創世紀

這里的@Configuration對我們來說并不陌生,它就是JavaConfig形式的Spring IoC容器的配置類使用的那個@Configuration,既然SpringBoot應用骨子里就是一個Spring應用,那么,自然也需要加載某個IoC容器的配置,而SpringBoot社區推薦使用基于JavaConfig的配置形式,所以,很明顯,這里的啟動類標注了@Configuration之后,本身其實也是一個IoC容器的配置類!
很多SpringBoot的代碼示例都喜歡在啟動類上直接標注@Configuration或者@SpringBootApplication,對于初接觸SpringBoot的開發者來說,其實這種做法不便于理解,如果我們將上面的SpringBoot啟動類拆分為兩個獨立的Java類,整個形勢就明朗了:

@Configuration @EnableAutoConfiguration @ComponentScan public class DemoConfiguration {@Beanpublic Controller controller() {return new Controller();} } public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoConfiguration.class, args);} }

所以,啟動類DemoApplication其實就是一個標準的Standalone類型Java程序的main函數啟動類,沒有什么特殊的。
而@Configuration標注的DemoConfiguration定義其實也是一個普通的JavaConfig形式的IoC容器配置類,沒啥新東西,全是Spring框架里的概念!

不要被這個長篇大論弄模糊了,這個其實在以前學習Spring中也有這些注解,Spring容器中為了簡化XMl配置,允許使用JavaConfig注冊一個Bean。就是使用的是@Configuration,每個擁有注解@Bean的函數的返回值,都將會在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其實也沒啥“創意”,各位是否還記得Spring框架提供的各種名字為@Enable開頭的Annotation定義?比如@EnableScheduling、@EnableCaching、@EnableMBeanExport等,@EnableAutoConfiguration的理念和“做事方式”其實一脈相承,簡單概括一下就是,借助@Import的支持,收集和注冊特定場景相關的bean定義:
* @Enable Scheduling是通過@Import將Spring調度框架相關的bean定義都加載到IoC容器。
* @Enable M Bean Export是通過@Import將JMX相關的bean定義加載到IoC容器。

而@EnableAutoConfiguration也是借助@Import的幫助,將所有符合自動配置條件的bean定義加載到IoC容器,僅此而已!
@EnableAutoConfiguration作為一個復合Annotation,其自身定義關鍵信息如下:

@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(EnableAutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration {... }

其中,最關鍵的要屬@Import(EnableAutoConfigurationImportSelector.class),借 助EnableAutoConfigurationImportSelector, @EnableAutoConfiguration可以幫助SpringBoot應用將所有符合條件的@Configuration配置都加載到當前SpringBoot創建并使用的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使用的話,它更多是提供一種配置查找的功能支持,即根據@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配置文件中摘錄的一段內容,可以很好地說明問題。
以,@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執行流程

SpringApplication的run方法的實現是我們本次旅程的主要線路, 該方法的主要流程大體可以歸納如下:

  • 如果我們使用的是SpringApplication的靜態run方法,那么,這個方法里面首先需要創建一個SpringApplication對象實例,然后調用這個創建好的SpringApplication的實例run方法。在SpringApplication實例初始化的時候,它會提前做幾件事情:
    • 根據classpath里面是否存在某個特征類(org.springframework.web.context.ConfigurableWebApplicationContext)來決定是否應該創建一個為Web應用使用的ApplicationContext類型,還是應該創建一個標準Standalone應用使用的ApplicationContext類型。
    • 使用SpringFactoriesLoader在應用的classpath中查找并加載所有可用的ApplicationContextInitializer。
    • 使用SpringFactoriesLoader在應用的classpath中查找并加載所有可用的ApplicationListener。
    • 推斷并設置main方法的定義類。
  • SpringApplication實例初始化完成并且完成設置后,就開始執行run方法的邏輯了,方法執行伊始,首先遍歷執行所有通過SpringFactoriesLoader可以查找到并加載的SpringApplicationRunListener,調用它們的started()方法,告訴這些SpringApplicationRunListener,“嘿,SpringBoot應用要開始執行咯!”。
  • 創建并配置當前SpringBoot應用將要使用的Environment(包括配置要使用的PropertySource以及Profile)。
  • 遍歷調用所有SpringApplicationRunListener的environmentPrepared()的方法,告訴它們:“當前SpringBoot應用使用的Environment準備好咯!”。
  • 如果SpringApplication的showBanner屬性被設置為true,則打印banner(SpringBoot 1.3.x版本,這里應該是基于Banner.Mode決定banner的打印行為)。這一步的邏輯其實可以不關心,我認為唯一的用途就是“好玩”(Just For Fun)。
  • 根據用戶是否明確設置了applicationContextClass類型以及初始化階段的推斷結果,決定該為當前SpringBoot應用創建什么類型的ApplicationContext并創建完成,然后根據條件決定是否添加ShutdownHook,決定是否使用自定義的BeanNameGenerator,決定是否使用自定義的ResourceLoader,當然,最重要的,將之前準備好的Environment設置給創建好的ApplicationContext使用。
  • ApplicationContext創建好之后,SpringApplication會再次借助Spring-FactoriesLoader,查找并加載classpath中所有可用的ApplicationContext-Initializer,然后遍歷調用這些ApplicationContextInitializer的initialize (applicationContext)方法來對已經創建好的ApplicationContext進行進一步的處理。
  • 遍歷調用所有SpringApplicationRunListener的contextPrepared()方法, 通知它們:“SpringBoot應用使用的ApplicationContext準備好啦!”
  • 最核心的一步,將之前通過@EnableAutoConfiguration獲取的所有配置以及其他形式的IoC容器配置加載到已經準備完畢的ApplicationContext。
  • 遍歷調用所有SpringApplicationRunListener的contextLoaded()方法,告知所有SpringApplicationRunListener,ApplicationContext”裝填完畢”!
  • 調用ApplicationContext的refresh()方法,完成IoC容器可用的最后一道工序。
  • 查找當前ApplicationContext中是否注冊有CommandLineRunner,如果有,則遍歷執行它們。
  • 正常情況下,遍歷執行SpringApplicationRunListener的finished()方法,告知它們:“搞定!”。(如果整個過程出現異常,則依然調用所有SpringApplicationRunListener的finished()方法,只不過這種情況下會將異常信息一并傳入處理)。
  • 至此,一個完整的SpringBoot應用啟動完畢!

    整個過程看起來冗長無比,但其實很多都是一些事件通知的擴展點,如果我們將這些邏輯暫時忽略,那么,其實整個SpringBoot應用啟動的邏輯就可以壓縮到極其精簡的幾步。

    參考文章

    • 《SpringBoot揭秘 快速構建微服務體系》 第三章
    創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

    總結

    以上是生活随笔為你收集整理的学习Spring Boot:(二)启动原理的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。