Spring Boot啟動
- 關鍵類、方法:ConfigurableApplicationContext SpringApplication#run。
new SpringApplication(primarySources).run(args);
類方法說明
- SpringApplication類
可以被用來從Java主方法中引導、啟動一個Spring應用的類。默認,類會執行下面步驟來引導你的應用:- 創建一個合適的ApplicationContext實例(依賴你的類路徑)。
- 注冊一個CommandLinePropertySource來暴露命令行參數為Spring屬性。
- 刷新應用上下位,加載所有的單例bean。
- 觸發任意的CommandLinerRunner bean。
在多數情況下,靜態run(Class, String[])可以直接從你的main方法調用,來引導你的應用。
對于更高級的配置,SpringApplication實例可以在被運行前創建和自定義:
SpringApplication application = new SpringApplication(MyApplication.class);
//...在這里自定義應用設置
application.run(args);
SpringApplication可以從各種源中讀取bean。通常建議@Configuration來引導你的應用,然而,你也可能從下面方式中設置getSources():
1. 由AnnotatedBeanDefinitionReader加載的全限定類名
2. 由XmlBeanDefinitionReader加載的XML資源位置,或者由GroovyBeanDefinitionReader加載的groovy腳本
3. ClassPathBeanDefinitionScanner掃描的包名
配置屬性也被綁定到SpringApplication。這讓動態設置SpringApplication屬性成為可能,像額外的源("spring.main.sources",一個CSV列表)標志來表示web環境("spring.main.web-application-type=none")或者關閉橫幅的("spring.main.banner-mode=off")。
- 方法SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources)
創建一個新的SpringApplication實例。應用上下文會從指定主要源加載bean(看SpringApplication類級別文檔。實例可以在調用run(String...)之前自定義)。 - 方法Collection<T> getSpringFactoriesInstance(Class<T> type, Class<?>[] paramenterTypes, Object... args)
- ResourceLoader接口
加載資源的策略接口(例如,類路徑或者文件系統資源)。org.springframework.context.ApplicationContext被要求提供這個功能,延申擴展org.springframework.core.io.support.ResourcePatternResolver支持。
DefaultResourceLoader是一個獨立實現,在ApplicationContext外是可用的,也被ResourceEditor使用。
Resource類型的bean屬性和Resource數組可以從字符串中填充,當運行在ApplicationContext中時,使用特殊的上下文資源加載策略。 - Resource getResource(String location):為給定的資源位置返回一個Resource處理。該處理應該總是可以重復使用的資源描述符,允許多次Resource#getInputStream()調用。
- 必須支持全限定URL,例如,"file:C:/test.dat"
- 必須支持類路徑偽限定URL,例如, "classpath:test.dat"
- 應該支持相對路徑,例如, "WEB-INF/test.dat"。(這會被具體實現,一般由ApplicationContext實現提供)
注意,一個Resource處理不表明一個存在的資源;你需要調用Resource#exists去檢查存在性。
- 類WebApplicationType
web應用可能類型的枚舉:NONE、SERVLET、REACTIVE。NONE:該類型應用不應該運行為web應用,不應該啟動內置web服務器;SERVLET: 該類型應用應該運行為基于servlet的web應用,應該啟動內置servlet web服務器;REACTIVE:該類型應用應該運行為響應式web應用,應該啟動內置響應式web服務器。 - 方法WebApplicationType deduceFromClassPath
從類路徑上推斷Web應用類型,SERVLET的標志類```{"javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext"}。默認返回SERVLET。 - 接口 ApplicationContextInitializer
初始化Spring ConfigurableApplicationContext的回調接口,優于被ConfigurableApplicationConetxt#refresh()刷新。
一般用在web應用上,就是要求應用上下文的一些編程方式的初始化。例如,根據ConfigurableApplicationContext#getEnvironment() 上下文的環境來注冊屬性元或者激活配置。查看ContextLoader和FrameworkServlet,支持聲明一個contextInitializerClasses上下文參數和初始化參數。
ApplicationContextInitializer處理器鼓勵去檢查是否Spring的org.springframework.core.Ordered 接口已經被實現,或者是否org.springframework.core.annotation.Order注解是否出現,來排序實例。 - 方法void initialize(C applicationContext):初始化給定的應用上下文
- 類SpringFactoriesLoader
用在框架內部的普通目的工廠加載機制。
SpringFactoriesLoader#loadFactories加載并且實例化#FACTORIES_RESOURCE_LOCATION文件中給定類型的工廠,它們可能出現在類路徑中的多個JAR文件中。spring.factories文件必須用Properties格式,在這種格式種,建時全限定的接口或者抽象類名稱,值時逗號分隔的實現類名列表。例如:
example.MyService=example.MyServiceImpl1,example.MyServiceImpl2
# example.MyService時接口的名稱,MyServiceImpl1和MyServiceImpl2是兩個實現
- 方法List<String> loadFactoryNames(Class<?> factoryType, ClassLoader classLoader)
加載#FACTORIES_RESOURCE_LOCATION中給定的工廠實現的全限定類名,使用給定的類加載器。 - 方法loadSpringFactories
FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories",從該文件中,加載資源,解析屬性,并且添加到緩存中。 - 方法createSpringFactoriesInstances
利用反射,加載、實例化上一步工廠配置中指定的名稱對應的類,并添加大鏈表中。 - instantiateFactory
使用反射,創建工廠實現類的實例。 - 方法 setInitializers
設置將會應用到Spring ApplicationContext的ApplicationCOntextInitializer - 接口ApplicationListener
函數式接口。由應用事件監聽器實現的接口。基于標準的java.util.EventListener接口,用于觀察者設計模式。
在Spring 3.0時,一個ApplicationListener通常可以聲明感興趣的事件類型。當用Spring ApplicationContext注冊時,事件會相應地被過濾,監聽器只在匹配的事件對象被調用。 - onApplicationEvent
處理一個應用事件 - EventListener
所有事件監聽器接口必須繼承的標記接口 - ApplicationEvent
被所有應用事件繼承的類。抽象是因為直接發布通用事件是沒有意義的。 - ApplicationEventMulticaster
被可以管理許多ApplicationListener對象,并且可以發布事件給它們的對象實現的接口。
org.springframework.context.ApplicationEventPublisher,一般一個Spring org.springframework.context.ApplicationContext,可以使用ApplicationEventMulticaster作為實際發布事件的委派。 - deduceMainApplicationClass
根據執行點的StackTraceElement,棧幀來與"main"比較,判斷主應用類。 - StopWatch
簡單的秒表,允許許多任務的時間點,暴露總共運行事件和每個命名任務的運行事件。隱藏Sys#nanoTime()的使用,提供應用代碼的可讀性,減少計算錯誤的可能性。注意,這個對象不是設計成線程安全的,并且不使用同步。這個類通常被用于驗證概念性證明工作中和開發中的性能,而不是作為生產應用的部分。在Spring Framework 5.2中,運行時被跟蹤,并且以毫秒報告。 - start()
開啟一個未命名的任務。如果未先調用這個方法,那么stop()或者時機方法的結果是未定義的。 - ConfigurableApplicationContext
由大多數應用上下文(如果不是所有)實現的SPI接口。
提供功能配置一個應用上下文,加上在org.springframework.context.ApplicationContext接口中的應用上下文客戶端方法。配置和生命周期方法在這里封裝,未了避免讓它們對ApplicationContext客戶端代碼明顯。出現的方法應該只在啟動和關閉代碼中使用。 - SpringBootExceptionReporter
函數式接口。用來支持SpringApplication啟動錯的自定義報告。SpringBootExceptionReporter通過SpringFactoriesLoader加載,并且必須聲明由一個單一ConfigurableApplicationContext參數的公共構造器。 - boolean reportException
報告一個啟動失敗給用戶 - SpringApplicationRunListeners
一組SpringApplicationRunListener。 - SpringApplicationRunListener
SpringApplication#run方法的監聽器。SpringApplicationRunListener通過SpringFactoriesLoader加載,并且應該聲明一個公共構造器,接收一個SpringApplication實例,和一個String[] 參數。一個新的SpringApplicationRunListener實例會為每次運行創建。 - 類ApplicationStartingEvent
盡早發布的事件,只要SpringApplication已經被啟動——在Environment或者ApplicationContext可用之前,但是在ApplicationListener已經被注冊后。事件源是SpringAplication自身,但是小心在早期階段使用它的內部狀態過多,因為它可能在后面的生命周期中被修改。 - 接口ConfigurableEnvironment
被多數Environment類型實現的接口。提供功能:設置激活、默認profile、操作底層屬性源。允許客戶端通過ConfigurablePropertyResolver超接口設置、驗證要求的屬性、自定義邊界服務等等。
操作屬性源。屬性元可以被移除、重排序或者替換;并且額外的屬性元可以使用MutablePropertySources實例添加,就是從getPropertySources()返回的。下面的例子依據ConfigurableEnvironment的StandardEnvironment實現,但是通常對任何實現可用,即時默認屬性元可能不同。
例子:添加一個有更高搜索優先級的新屬性源:
ConfigurableEnvironment environment = new StandardEnvironment();
MutablePropertySources propertySources = environment.getPropertySources();
Map<String, String> myMap = new HashMap<>();
myMap.put("xyz", "myValue");
propertySources.addFirst(new MapPropertySource("My_MAP", myMap));
例子:移除默認系統屬性源
MutablePropertySources propertySources = environment.getPropertySources();
propertySources.remove(StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME);
例子:為了測試目的,模擬系統環境
MutablePropertySources propertySources = environment.getPropertySources();
MockPropertySource mockEnvVars = new MockPropertySource().withProperty("xyz", "myValue");
propertySources.replace(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME);
當一個Environment被ApplicationContext使用時,有一點是比較重要的,就是PropertySource操作要在上下文的org.springframework.context.support.AbstractApplicationContext#refresh()方法調用之前執行。這確保所有屬性源在容器引導過程中都可用,包括通過org.springframework.context.support.PropertySourcesPlaceholderConfigurer屬性占位符使用。
- prepareEnvironment
- 創建Env
- 配置Env,就是屬性、profile
- 向監聽器發送env準備好的事件
- 綁定env到SpringApplication
- 返回env對象
- configureIgnoreBeanInfo(COnfigurableEnvironment environment)
- createApplicationContext
根據應用類型,反射實例化上下文類:SERVLET-org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;REACTIVE-org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;default-org.springframework.context.annotation.AnnotationConfigApplicationContext - prepareContext()
- 給上下文設置env
- 后置處理應用上下文。應用任何緊密相關的后置處理ApplicationContext,如果需要,子類可以應用額外的處理:配置bean名稱生成器、設置資源加載器、添加便捷服務
- 應用任何ApplicationContextInitializer到上下文,在上下文被刷新前。
- 獲取初始化器。返回要被應用到Spring ApplicationContext的ApplicationContextInitializer集合
- 給監聽器發送上下文已準備好事件。就是ApplicationContext已經被創建、準備好,但是在源被加載前調用
- 獲取上下文內部的bean工廠,主備手動注冊各種bean
- 加載源的bean到應用上下文
- 給監聽器發送上下文準備好的事件。在應用上下文已經被加載,但是在應用上下文被刷新前調用。
- refreshContext()
刷新應用上下文。最后調用的是一個同步方法。一次只能有一個線程調用。刷新配置的持久化表示,可能是XML文件、屬性文件或者關系型數據庫 - refresh()
- prepareRefresh():為刷新準備這個上下文,設置它的啟動日期和激活標志,包括執行屬性源的初始化
- 設置啟動日期
- 設置激活標志為true
- 初始化屬性源。初始化在上下文環境中的任意占位符屬性源。用實際實例替換存根屬性源
- 驗證所有被標記為要求的屬性為可解析的:看ConfigurablePropertyResolver#setRequiredProperties
- 存儲預刷新ApplicationListeners
- 允許所有早期ApplicationEvents集合,一旦廣播可用就發布
- obtainFreshbeanFactory():告訴子類刷新內部bean工廠。其實就是執行真實的配置加載,返回bean工廠。
- prepareBeanFactory():準備bean工廠,在這個上下文中使用該bean工廠。就是配置該工廠的標準上下文特征,例如上下文的類加載器和后置處理器。
- postProcessBeanFactory():允許在上下文子類中bean工廠的后置處理。在bean工廠的標準初始化后,修改該應用上下文的內部bean工廠。所有bean定義會被已經加載,但是還沒有bean已經被實例化。這允許在某種ApplicationContext實現中注冊特殊的BeanPostProcessors等等。
- invokeBeanFactoryPostProcessors():調用在該上下文中注冊為bean的工廠處理器。實例化并且調用所有注冊的BeanFactoryPostProcessor bean。
- registerBeanPostProcessors():注冊bean處理器,攔截bean創建
- initMessageSource():為這個上下文初始化消息源
- initApplicationEventMulticaster():為這個上下文初始化事件廣播。初始化ApplicationEventMulticaster。如果在該上下文中沒有定義,使用SimpleApplicationEventMulticaster。現在才注冊???
- onRefresh():初始化其他在特定上下文子類中的具體bean
- registerListeners():檢查監聽器bean,并且注冊它們
- finishBeanFactoryInitialization():初始化所有保留的(非延遲初始化)單例。完成這個上下文的bean工廠的初始化,實例化所有剩余單例bean。
- finishRefresh():發布相應的事件
- destroyBeans():銷毀已經創建的單例,避免懸掛資源
- cancelRefresh():重置active標志
- resetCommonCaches():重置Spring內核中公共的內省緩存,因為我們可能不再需要單例bean的元數據。
- prepareRefresh():為刷新準備這個上下文,設置它的啟動日期和激活標志,包括執行屬性源的初始化
- AbstractAplicationContext類還是很重要的
- afterRefresh()
在上下文已經被刷新后調用 - stop()
停止秒表 - stated()
給監聽器發送事件,就是上下文已經被刷新,并且應用已經啟動,但是CommandLineRunner和ApplicationRunner還沒有被調用
36.接口 ApplicationRunner
一個函數式ean包含在SpringApplication中時,它是否應該運行。多個ApplicationRunner bean可以被定義在相同的應用上下文中,并且可以用Ordered接口或者@Order排序。 - running()
在run方法完成前,立刻調用,當應用上下文已經被刷新,并且所有的CommandLineRunner和ApplicationRunner已經被調用后。