Spring Boot SpringApplication啟動類(二)
目錄
- 前言
- 1、起源
- 2、SpringApplication 執行階段
- 2.1 SpringApplicationRunListeners 結構
- 2.1.1 SpringApplicationRunListener 事件和監聽機制
- 2.1.2 SimpleApplicationEventMulticaster 廣播器
- 2.2 ApplicationArguments 載入啟動引數
- 2.3 ConfigurableEnvironment 載入外部化配置
- 2.4 ConfigurableApplicationContext 建立 Spring 應用上下文
- 2.1 SpringApplicationRunListeners 結構
- 3、總結
前言
最近在學習Spring Boot相關的課程,過程中以筆記的形式記錄下來,方便以後回憶,同時也在這裡和大家探討探討,文章中有漏的或者有補充的、錯誤的都希望大家能夠及時提出來,本人在此先謝謝了!
開始之前呢,希望大家帶著幾個問題去學習:
1、Spring Boot SpringApplication 是什麼?
2、整體流程或結構是怎樣的?
3、重點內容或者核心部分是什麼?
4、怎麼實現的?
5、是怎麼和 Spring 關聯起來的?
這是對自我的提問,我認為帶著問題去學習,是一種更好的學習方式,有利於加深理解。好了,接下來進入主題。
1、起源
上篇文章我們講了 SpringApplication
的準備階段,在這個階段,完成了執行時所需要準備的資源,如:initializers
、listeners
等。而這篇文章我們就來講講 SpringApplication
的執行階段,在這個階段,它是如何啟動 Spring
應用上下文的,且如何與 Spring
事件結合起來,形成完整的 SpringApplication
生命週期的。
注:本篇文章所用到的
Spring Boot
版本是2.1.6.BUILD-SNAPSHOT
2、SpringApplication 執行階段
上篇文章我們講了 SpringApplication
的構造方法,這裡我們就來講講 SpringApplication
的核心,也就是run方法,程式碼如下:
public class SpringApplication {
...
public ConfigurableApplicationContext run(String... args) {
// 這是 Spring 的一個計時器,計算程式碼的執行時間(ms級別)
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 這倆變數在後面賦值處進行說明
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
// 用來設定java.awt.headless屬性值
configureHeadlessProperty();
// 該物件屬於組合模式的實現,核心是內部關聯的 SpringApplicationRunListener 集合,SpringApplicationRunListener 是 Spring Boot 的執行時監聽器
SpringApplicationRunListeners listeners = getRunListeners(args);
// 會在不同的階段呼叫對應的方法,這裡表示啟動run方法被呼叫
listeners.starting();
try {
// 用來獲取 SpringApplication.run(args)傳入的引數
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 獲取 properties 配置檔案
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
// 設定 spring.beaninfo.ignore 的屬性值,判斷是否跳過搜尋BeanInfo類
configureIgnoreBeanInfo(environment);
// 這裡是專案啟動時,控制檯列印的 Banner
Banner printedBanner = printBanner(environment);
// 這裡就是建立 Spring 應用上下文
context = createApplicationContext();
// 獲取 spring.factories 中key為 SpringBootExceptionReporter 的類名集合
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// 這裡是準備 Spring 應用上下文
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 這裡是啟動 Spring 應用上下文,底層呼叫的是 ApplicationContext 的 refresh() 方法,到這裡就正式進入了 Spring 的生命週期,同時,SpringBoot的自動裝配特性也隨之啟動
refreshContext(context);
// 裡面是空的,猜測應該是交由開發人員自行擴充套件
afterRefresh(context, applicationArguments);
stopWatch.stop();
// 這裡列印啟動資訊
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
// ApplicationContext 啟動時,呼叫該方法
listeners.started(context);
// 專案啟動後,做的一些操作,開發人員可自行擴充套件
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
// ApplicationContext 啟動完成時,呼叫該方法
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
...
}
上面就是整個過程的概覽,可以看到,在執行階段執行的操作比較多,雖然看起來雜亂無章,但其實還是有規律可循的。比如,執行的 SpringApplicationRunListeners
中的階段方法,剛啟動階段的 starting
、已啟動階段的 started
、啟動完成階段的 running
等。還有對應的 Spring
應用上下文的建立、準備、啟動操作等。接下來,就對裡面的幾個核心物件進行討論。
2.1 SpringApplicationRunListeners 結構
我們先來看看 SpringApplicationRunListeners
物件,從程式碼可以看出該物件是由 getRunListeners
方法建立的:
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
可以看到,通過傳入的 getSpringFactoriesInstances
方法的返回值,執行 SpringApplicationRunListeners
的構造方法,進行物件的建立。接著看 getSpringFactoriesInstances
方法:
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
看到這大家應該比較熟悉了,通過前面幾篇文章的討論我們知道,該方法通過 SpringFactoriesLoader.loadFactoryNames
返回所有 classpass 下的 spring.factories
檔案中 key 為 SpringApplicationRunListener
的實現類集合。如 Spring Boot 的內建實現:
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
最後,就是將該集合傳入 SpringApplicationRunListeners
的構造方法:
class SpringApplicationRunListeners {
...
private final List<SpringApplicationRunListener> listeners;
SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {
this.log = log;
this.listeners = new ArrayList<>(listeners);
}
public void starting() {
for (SpringApplicationRunListener listener : this.listeners) {
listener.starting();
}
}
...
}
裡面是將集合賦值到 listeners
屬性,可以看到 SpringApplicationRunListeners
屬於組合模式的實現,核心其實是內部關聯的 SpringApplicationRunListener
物件集合,當外部呼叫該階段方法時,就會迭代執行集合中 SpringApplicationRunListener
對應的方法。所以接下來我們就來討論 SpringApplicationRunListener
。
2.1.1 SpringApplicationRunListener 事件和監聽機制
SpringApplicationRunListener
負責在 SpringBoot
的不同階段廣播相應的事件,然後呼叫實際的 ApplicationListener
類,在該類的 onApplicationEvent
方法中,根據不同的 Spring Boot
事件執行相應操作。整個過程大概如此,接下來進行詳細討論,先來看看 SpringApplicationRunListener
定義:
public interface SpringApplicationRunListener {
// 在run()方法開始執行時被呼叫,表示應用剛剛啟動,對應的 Spring Boot 事件為 ApplicationStartingEvent
void starting();
// ConfigurableEnvironment 構建完成時呼叫,對應的 Spring Boot 事件為 ApplicationEnvironmentPreparedEvent
void environmentPrepared(ConfigurableEnvironment environment);
// ApplicationContext 構建完成時呼叫,對應的 Spring Boot 事件為 ApplicationContextInitializedEvent
void contextPrepared(ConfigurableApplicationContext context);
// ApplicationContext 完成載入但還未啟動時呼叫,對應的 Spring Boot 事件為 ApplicationPreparedEvent
void contextLoaded(ConfigurableApplicationContext context);
// ApplicationContext 已啟動,但 callRunners 還未執行時呼叫,對應的 Spring Boot 事件為 ApplicationStartedEvent
void started(ConfigurableApplicationContext context);
// ApplicationContext 啟動完畢被呼叫,對應的 Spring Boot 事件為 ApplicationReadyEvent
void running(ConfigurableApplicationContext context);
// 應用出錯時被呼叫,對應的 Spring Boot 事件為 ApplicationFailedEvent
void failed(ConfigurableApplicationContext context, Throwable exception);
}
我們來看看它的實現類,也就是上面載入的 spring.factories
檔案中的 EventPublishingRunListener
類,該類也是 Spring Boot
內建的唯一實現類,具體廣播事件的操作在該類中進行,程式碼如下:
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
private final SpringApplication application;
private final String[] args;
private final SimpleApplicationEventMulticaster initialMulticaster;
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
@Override
public void starting() {
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
...
}
可以看到,通過構造方法建立 EventPublishingRunListener
例項的過程中,呼叫了 getListeners
方法,將 SpringApplication
中所有 ApplicationListener
監聽器關聯到了 initialMulticaster
屬性中。沒錯,這裡的 ApplicationListener
監聽器就是上篇文章中在 SpringApplication
準備階段從 spring.factories
檔案載入的 key 為 ApplicationListener
的實現類集合,該實現類集合全部重寫了 onApplicationEvent
方法。
2.1.2 SimpleApplicationEventMulticaster 廣播器
這裡又引出了另一個類, 也就是 SimpleApplicationEventMulticaster
,該類是 Spring
的事件廣播器,也就是通過它來廣播各種事件。接著,當外部迭代的執行到 EventPublishingRunListener
的 starting
方法時,會通過 SimpleApplicationEventMulticaster
的 multicastEvent
方法進行事件的廣播,這裡廣播的是 ApplicationStartingEvent
事件,我們進入 multicastEvent
方法:
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
...
@Override
public void multicastEvent(ApplicationEvent event) {
multicastEvent(event, resolveDefaultEventType(event));
}
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
}
通過 getApplicationListeners
方法,根據事件型別返回從上面關聯的 ApplicationListener
集合中篩選出匹配的 ApplicationListener
集合,根據 Spring Boot
版本的不同,在這個階段獲取到的監聽器也有可能不同,如 2.1.6.BUILD-SNAPSHOT
版本返回的是:
然後依次遍歷這些監聽器,同步或非同步的呼叫 invokeListener
方法:
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
}
catch (Throwable err) {
errorHandler.handleError(err);
}
}
else {
doInvokeListener(listener, event);
}
}
...
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
// -> let's suppress the exception and just log a debug message.
Log logger = LogFactory.getLog(getClass());
if (logger.isTraceEnabled()) {
logger.trace("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}
可以看到,最終呼叫的是 doInvokeListener
方法,在該方法中執行了 ApplicationListener
的 onApplicationEvent
方法,入參為廣播的事件物件。我們就拿其中一個的監聽器來看看 onApplicationEvent
中的實現,如 BackgroundPreinitializer
類:
public class BackgroundPreinitializer implements ApplicationListener<SpringApplicationEvent> {
...
@Override
public void onApplicationEvent(SpringApplicationEvent event) {
if (!Boolean.getBoolean(IGNORE_BACKGROUNDPREINITIALIZER_PROPERTY_NAME)
&& event instanceof ApplicationStartingEvent && preinitializationStarted.compareAndSet(false, true)) {
performPreinitialization();
}
if ((event instanceof ApplicationReadyEvent || event instanceof ApplicationFailedEvent)
&& preinitializationStarted.get()) {
try {
preinitializationComplete.await();
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
...
}
在該方法中,通過 instanceof
判斷事件的型別,從而進行相應的操作。該監聽器主要的操作是新建一個後臺執行緒去執行那些耗時的初始化工作,包括驗證器、訊息轉換器等。LoggingApplicationListener
監聽器則是對 Spring Boot
的日誌系統做一些初始化的前置操作。另外兩個監聽器在該階段無任何操作。
至此,SpringBoot
事件機制的整體流程大概如此,我們簡要回顧一下幾個核心元件:
SpringApplicationRunListeners:首先,在
run
方法的執行過程中,通過該類在SpringBoot
不同的階段呼叫不同的階段方法,如在剛啟動階段呼叫的starting
方法。SpringApplicationRunListener:而
SpringApplicationRunListeners
屬於組合模式的實現,它裡面關聯了SpringApplicationRunListener
實現類集合,當外部呼叫階段方法時,會迭代執行該集合中的階段方法。實現類集合是spring.factories
檔案中定義好的類。這裡是一個擴充套件點,詳細的後面述說。EventPublishingRunListener:該類是
Spring Boot
內建的SpringApplicationRunListener
唯一實現類,所以,當外部呼叫各階段的方法時,真正執行的是該類中的方法。SimpleApplicationEventMulticaster:在階段方法中,會通過
Spring
的SimpleApplicationEventMulticaster
事件廣播器,廣播各個階段對應的事件,如這裡的starting
方法廣播的事件是ApplicationStartingEvent
。ApplicationListener:最後
ApplicationListener
的實現類也就是Spring Boot
監聽器會監聽到廣播的事件,根據不同的事件,進行相應的操作。這裡的Spring Boot
監聽器是也是在spring.factories
中定義好的,這裡我們也可自行擴充套件。
到這裡 Spring Boot
事件監聽機制差不多就結束了,值得注意的是 Spring Boot
監聽器實現的是 Spring
的 ApplicationListener
類,事件類最終繼承的也是 Spring
的 ApplicationEvent
類,所以,Spring Boot
的事件和監聽機制都基於 Spring
而實現的。
2.2 ApplicationArguments 載入啟動引數
當執行完 listeners.starting
方法後,接著進入構造 ApplicationArguments
階段:
public class SpringApplication {
...
public ConfigurableApplicationContext run(String... args) {
...
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
...
}
}
...
}
該類是用於簡化 Spring Boot
應用啟動引數的封裝介面,我們啟動專案時輸入的命令引數會封裝在該類中。一種是通過 IDEA 輸入的引數,如下:
另一種是 springboot
jar包執行時傳遞的引數:cmd中執行java -jar xxx.jar name=張三 pwa=123
。
然後,可以通過 @Autowired
注入 ApplicationArguments
的方式進行使用:
public class Test {
@Autowired
private ApplicationArguments applicationArguments;
public void getArgs() {
// 獲取 args 中的所有 non option 引數
applicationArguments.getNonOptionArgs();
// 獲取 args 中所有的 option 引數的 name
applicationArguments.getOptionNames();
// 獲取傳遞給應用程式的原始未處理引數
applicationArguments.getSourceArgs();
// 獲取 args 中指定 name 的 option 引數的值
applicationArguments.getOptionValues("nmae");
// 判斷從引數中解析的 option 引數是否包含指定名稱的選項
applicationArguments.containsOption("name");
}
}
2.3 ConfigurableEnvironment 載入外部化配置
接著進入構造 ConfigurableEnvironment
的階段,該類是用來處理我們外部化配置的,通俗點講就是處理 properties
的檔案,提供對配置檔案的基礎操作。此外,Spring Boot
存在預設配置檔案,也就是 application.properties
。這裡我們進行大致的瞭解即可,後面會有專門的文章討論這塊內容。我們進入建立該類的 prepareEnvironment
方法:
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
listeners.environmentPrepared(environment);
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
這裡通過 getOrCreateEnvironment
方法返回具體的 Environment
:
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
switch (this.webApplicationType) {
case SERVLET:
return new StandardServletEnvironment();
case REACTIVE:
return new StandardReactiveWebEnvironment();
default:
return new StandardEnvironment();
}
}
可以看到,這裡通過 webApplicationType
屬性來判斷當前應用的型別,有 Servlet
、 Reactive
、 非Web 3種類型,該屬性也是在上篇文章中 SpringApplication
準備階段確定的,這裡我們通常都是 Servlet
型別,返回的是 StandardServletEnvironment
例項。
之後,還呼叫了 SpringApplicationRunListeners
的 environmentPrepared
階段方法,表示 ConfigurableEnvironment
構建完成,同時向 Spring Boot
監聽器釋出 ApplicationEnvironmentPreparedEvent
事件。監聽該事件的監聽器有:
2.4 ConfigurableApplicationContext 建立 Spring 應用上下文
這裡通過 createApplicationContext
方法建立 Spring
應用上下文,實際上 Spring
的應用上下文才是驅動 Spring Boot
的核心引擎:
public class SpringApplication {
...
public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
+ "annotation.AnnotationConfigApplicationContext";
public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."
+ "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";
public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
+ "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";
...
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass",
ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
...
}
這裡也是通過 webApplicationType
屬性來確定應用型別從而建立 String
上下文,上篇文章說到該屬性值是在 Spring Boot
準備階段推匯出來的。這裡我們的應用型別是 Servlet
,所以建立的是 AnnotationConfigServletWebServerApplicationContext
物件。建立完 Spring
應用上下文之後,執行 prepareContext
方法進入準備上下文階段:
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}
我們來看看主要做了哪些操作:
設定了
Spring
應用上下文的ApplicationArguments
,上面說過是處理外部化配置的,具體型別為StandardServletEnvironment
。Spring
應用上下文後置處理,主要是覆蓋當前Spring
應用上下文預設所關聯的ResourceLoader
和ClassLoader
。執行
Spring
的初始化器,上篇文章說過在Spring Boot
準備階段初始化了一批在spring.factories
檔案中定義好的ApplicationContextInitializer
,這裡就是執行它們的initialize
方法,同時這裡也是一個擴充套件點,後面詳細討論。執行
SpringApplicationRunListeners
的contextPrepared
階段方法,表示ApplicationContext
準備完成,同時向Spring Boot
監聽器釋出ApplicationContextInitializedEvent
事件 。將
springApplicationArguments
和springBootBanner
註冊為Bean
。載入
Spring
應用上下文的配置源,也是在上篇文章Spring Boot
準備階段獲取的primarySources
和sources
,primarySources
來源於SpringApplication
構造器引數,sources
則來源於自定義配置的setSources
方法。最後執行
SpringApplicationRunListeners
的contextLoaded
階段方法,表示ApplicationContext
完成載入但還未啟動,同時向Spring Boot
監聽器釋出ApplicationPreparedEvent
事件 。
接下來就是真正啟動階段,執行的是 refreshContext
方法:
private void refreshContext(ConfigurableApplicationContext context) {
refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext) applicationContext).refresh();
}
可以看到,底層呼叫的是 AbstractApplicationContext
的 refresh
方法,到這裡 Spring
應用正式啟動,Spring Boot
核心特性也隨之啟動,如自動裝配。隨後執行 SpringApplicationRunListeners
的 started
階段方法,表示 ApplicationContext
已啟動,同時向 Spring Boot
監聽器釋出 ApplicationStartedEvent
事件 。但還未啟動完成,後面還有一個 callRunners
方法,一般來講,裡面執行一些我們自定義的操作。之後 Spring
應用才算啟動完成,隨後呼叫 running
方法,釋出 ApplicationReadyEvent
事件。至此,SpringApplication
執行階段結束。
3、總結
最後來對 SpringApplication
執行階段做一個總結。這個階段核心還是以啟動 Spring
應用上下文為主,同時根據應用型別來初始化不同的上下文物件,但這些物件的基類都是 Spring
的 ConfigurableApplicationContext
類。且在啟動的各個階段中,使用 SpringApplicationRunListeners
進行事件廣播,回撥 Spring Boot
的監聽器。同時還初始化了 ApplicationArguments
、ConfigurableEnvironment
等幾個元件。下篇文章我們就來討論 Spring Boot
的外部化配置部分,來看看為什麼外部的各個元件,如 Redis
、Dubbo
等在 properties
檔案中進行相應配置後,就可以正常使用。
以上就是本章的內容,如過文章中有錯誤或者需要補充的請及時提出,本人感激不盡。
參考:
《Spring Boot 程式設計思想》
https://www.cnblogs.com/youzhibing/p/9603119.html
https://www.jianshu.com/p/b86a7c8b3442
https://www.cnblogs.com/duanxz/p/11243271.html
https://www.jianshu.com/p/7a674c59