程式入口
SpringApplication.run(BeautyApplication.class, args);
執行此方法來載入整個SpringBoot的環境。
1. 從哪兒開始?
SpringApplication.java
/**
* Run the Spring application, creating and refreshing a new
* {@link ApplicationContext}.
* @param args the application arguments (usually passed from a Java main method)
* @return a running {@link ApplicationContext}
*/
public ConfigurableApplicationContext run(String... args) {
//...
}
呼叫SpringApplication.java 中的 run 方法,目的是載入Spring Application,同時返回 ApplicationContext。
2. 執行了什麼?
2.1 計時
記錄整個Spring Application的載入時間!
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// ...
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
2.2 宣告
指定 java.awt.headless,預設是true 一般是在程式開始啟用headless模式,告訴程式,現在你要工作在Headless mode下,就不要指望硬體幫忙了,你得自力更生,依靠系統的計算能力模擬出這些特性來。
private void configureHeadlessProperty() {
System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty(
SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
2.4 配置監聽併發布應用啟動事件
SpringApplicationRunListener 負責載入 ApplicationListener事件。
SpringApplicationRunListeners listeners = getRunListeners(args);
// 開始
listeners.starting();
// 處理所有 property sources 配置和 profiles 配置,準備環境,分為標準 Servlet 環境和標準環境
ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);
// 準備應用上下文
prepareContext(context, environment, listeners, applicationArguments,printedBanner);
// 完成
listeners.started(context);
// 異常
handleRunFailure(context, ex, exceptionReporters, listeners);
// 執行
listeners.running(context);
getRunListeners 中根據 type = SpringApplicationRunListener.class 去拿到了所有的 Listener 並根據優先順序排序。
對應的就是 META-INF/spring.factories 檔案中的 org.springframework.boot.SpringApplicationRunListener=org.springframework.boot.context.event.EventPublishingRunListener
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// 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;
複製程式碼
在 ApplicationListener 中 , 可以針對任何一個階段插入處理程式碼。
public interface SpringApplicationRunListener {
* Called immediately when the run method has first started. Can be used for very
* early initialization.
void starting();
* Called once the environment has been prepared, but before the
* {@link ApplicationContext} has been created.
* @param environment the environment
void environmentPrepared(ConfigurableEnvironment environment);
* Called once the {@link ApplicationContext} has been created and prepared, but
* before sources have been loaded.
* @param context the application context
void contextPrepared(ConfigurableApplicationContext context);
* Called once the application context has been loaded but before it has been
* refreshed.
void contextLoaded(ConfigurableApplicationContext context);
* The context has been refreshed and the application has started but
* {@link CommandLineRunner CommandLineRunners} and {@link ApplicationRunner
* ApplicationRunners} have not been called.
* @param context the application context.
* @since 2.0.0
void started(ConfigurableApplicationContext context);
* Called immediately before the run method finishes, when the application context has
* been refreshed and all {@link CommandLineRunner CommandLineRunners} and
* {@link ApplicationRunner ApplicationRunners} have been called.
void running(ConfigurableApplicationContext context);
* Called when a failure occurs when running the application.
* @param context the application context or {@code null} if a failure occurred before
* the context was created
* @param exception the failure
void failed(ConfigurableApplicationContext context, Throwable exception);
3. 每個階段執行的內容
3.1 listeners.starting();
在載入Spring Application之前執行,所有資源和環境未被載入。
3.2 prepareEnvironment(listeners, applicationArguments);
建立 ConfigurableEnvironment; 將配置的環境繫結到Spring Application中;
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.webApplicationType == WebApplicationType.NONE) {
environment = new EnvironmentConverter(getClassLoader())
.convertToStandardEnvironmentIfNecessary(environment);
ConfigurationPropertySources.attach(environment);
return environment;
3.3 prepareContext
配置忽略的Bean;
private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {
if (System.getProperty(
CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) {
Boolean ignore = environment.getProperty("spring.beaninfo.ignore",
Boolean.class, Boolean.TRUE);
System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME,
ignore.toString());
列印日誌-載入的資源
Banner printedBanner = printBanner(environment);
根據不同的WebApplicationType建立Context
context = createApplicationContext();
3.4 refreshContext
支援定製重新整理
* Register a shutdown hook with the JVM runtime, closing this context
* on JVM shutdown unless it has already been closed at that time.
* <p>This method can be called multiple times. Only one shutdown hook
* (at max) will be registered for each context instance.
* @see java.lang.Runtime#addShutdownHook
* @see #close()
void registerShutdownHook();
3.5 afterRefresh
重新整理後的實現方法暫未實現
* Called after the context has been refreshed.
* @param args the application arguments
protected void afterRefresh(ConfigurableApplicationContext context,
ApplicationArguments args) {
3.6 listeners.started(context);
到此為止, Spring Application的環境和資源都載入完畢了; 釋出應用上下文啟動完成事件; 執行所有 Runner 執行器 - 執行所有 ApplicationRunner 和 CommandLineRunner 這兩種執行器
// 啟動
callRunners(context, applicationArguments);
3.7 listeners.running(context);
觸發所有 SpringApplicationRunListener 監聽器的 running 事件方法
程式入口
SpringApplication.run(BeautyApplication.class, args);
執行此方法來載入整個SpringBoot的環境。
1. 從哪兒開始?
SpringApplication.java
/**
* Run the Spring application, creating and refreshing a new
* {@link ApplicationContext}.
* @param args the application arguments (usually passed from a Java main method)
* @return a running {@link ApplicationContext}
*/
public ConfigurableApplicationContext run(String... args) {
//...
}
呼叫SpringApplication.java 中的 run 方法,目的是載入Spring Application,同時返回 ApplicationContext。
2. 執行了什麼?
2.1 計時
記錄整個Spring Application的載入時間!
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// ...
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
2.2 宣告
指定 java.awt.headless,預設是true 一般是在程式開始啟用headless模式,告訴程式,現在你要工作在Headless mode下,就不要指望硬體幫忙了,你得自力更生,依靠系統的計算能力模擬出這些特性來。
private void configureHeadlessProperty() {
System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty(
SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
}
2.4 配置監聽併發布應用啟動事件
SpringApplicationRunListener 負責載入 ApplicationListener事件。
SpringApplicationRunListeners listeners = getRunListeners(args);
// 開始
listeners.starting();
// 處理所有 property sources 配置和 profiles 配置,準備環境,分為標準 Servlet 環境和標準環境
ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);
// 準備應用上下文
prepareContext(context, environment, listeners, applicationArguments,printedBanner);
// 完成
listeners.started(context);
// 異常
handleRunFailure(context, ex, exceptionReporters, listeners);
// 執行
listeners.running(context);
getRunListeners 中根據 type = SpringApplicationRunListener.class 去拿到了所有的 Listener 並根據優先順序排序。
對應的就是 META-INF/spring.factories 檔案中的 org.springframework.boot.SpringApplicationRunListener=org.springframework.boot.context.event.EventPublishingRunListener
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// 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;
}
複製程式碼
在 ApplicationListener 中 , 可以針對任何一個階段插入處理程式碼。
public interface SpringApplicationRunListener {
/**
* Called immediately when the run method has first started. Can be used for very
* early initialization.
*/
void starting();
/**
* Called once the environment has been prepared, but before the
* {@link ApplicationContext} has been created.
* @param environment the environment
*/
void environmentPrepared(ConfigurableEnvironment environment);
/**
* Called once the {@link ApplicationContext} has been created and prepared, but
* before sources have been loaded.
* @param context the application context
*/
void contextPrepared(ConfigurableApplicationContext context);
/**
* Called once the application context has been loaded but before it has been
* refreshed.
* @param context the application context
*/
void contextLoaded(ConfigurableApplicationContext context);
/**
* The context has been refreshed and the application has started but
* {@link CommandLineRunner CommandLineRunners} and {@link ApplicationRunner
* ApplicationRunners} have not been called.
* @param context the application context.
* @since 2.0.0
*/
void started(ConfigurableApplicationContext context);
/**
* Called immediately before the run method finishes, when the application context has
* been refreshed and all {@link CommandLineRunner CommandLineRunners} and
* {@link ApplicationRunner ApplicationRunners} have been called.
* @param context the application context.
* @since 2.0.0
*/
void running(ConfigurableApplicationContext context);
/**
* Called when a failure occurs when running the application.
* @param context the application context or {@code null} if a failure occurred before
* the context was created
* @param exception the failure
* @since 2.0.0
*/
void failed(ConfigurableApplicationContext context, Throwable exception);
}
3. 每個階段執行的內容
3.1 listeners.starting();
在載入Spring Application之前執行,所有資源和環境未被載入。
3.2 prepareEnvironment(listeners, applicationArguments);
建立 ConfigurableEnvironment; 將配置的環境繫結到Spring Application中;
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.webApplicationType == WebApplicationType.NONE) {
environment = new EnvironmentConverter(getClassLoader())
.convertToStandardEnvironmentIfNecessary(environment);
}
ConfigurationPropertySources.attach(environment);
return environment;
}
3.3 prepareContext
配置忽略的Bean;
private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {
if (System.getProperty(
CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) {
Boolean ignore = environment.getProperty("spring.beaninfo.ignore",
Boolean.class, Boolean.TRUE);
System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME,
ignore.toString());
}
}
列印日誌-載入的資源
Banner printedBanner = printBanner(environment);
根據不同的WebApplicationType建立Context
context = createApplicationContext();
3.4 refreshContext
支援定製重新整理
/**
* Register a shutdown hook with the JVM runtime, closing this context
* on JVM shutdown unless it has already been closed at that time.
* <p>This method can be called multiple times. Only one shutdown hook
* (at max) will be registered for each context instance.
* @see java.lang.Runtime#addShutdownHook
* @see #close()
*/
void registerShutdownHook();
3.5 afterRefresh
重新整理後的實現方法暫未實現
/**
* Called after the context has been refreshed.
* @param context the application context
* @param args the application arguments
*/
protected void afterRefresh(ConfigurableApplicationContext context,
ApplicationArguments args) {
}
3.6 listeners.started(context);
到此為止, Spring Application的環境和資源都載入完畢了; 釋出應用上下文啟動完成事件; 執行所有 Runner 執行器 - 執行所有 ApplicationRunner 和 CommandLineRunner 這兩種執行器
// 啟動
callRunners(context, applicationArguments);
3.7 listeners.running(context);
觸發所有 SpringApplicationRunListener 監聽器的 running 事件方法