Spring 應用的啟動類。
建立 ApplicationContext 範例
ApplicationContext 就是我們所說的容器範例。
註冊 CommandLinePropertySource
CommandLinePropertySource 的作用是將命令列引數輸出為 Spring 屬性。
重新整理 ApplicationContext
這一步驟包括諸多操作,並且會載入所有的單例 bean。
觸發 CommandLineRunner bean
CommandLineRunner 是一個介面,它只有一個 run() 方法。
凡是實現了此介面的類,如果被載入進容器,就會執行其 run() 方法。
容器中可以包含多個實現 CommandLineRunner 的 bean,執行順序可以遵從 Ordered 介面或者 @Order 註解設定。
SpringApplication 有諸多 bean 載入源:
AnnotatedBeanDefinitionReader
顧名思義,註解 bean 定義讀取。
XmlBeanDefinitionReader
xml 設定資源讀取。
ClassPathBeanDefinitionScanner
classpath 路徑掃描。
GroovyBeanDefinitionReader
... ...
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.bootstrapRegistryInitializers = new ArrayList<>(
getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
引數可以為 null,為 null 時,使用預設:
(this.resourceLoader != null) ? this.resourceLoader: new DefaultResourceLoader(null);
主要的 bean 定義來源。
web 應用型別判斷:
NONE:應用不會以 web 應用執行,且不會啟動內嵌 web 伺服器。
SERVLET:基於 servlet web 應用,執行於內嵌 web 伺服器。
REACTIVE:響應式 web 應用,執行於內嵌 web 伺服器。
BootstrapRegistryInitializer:回撥介面,用於 BootstrapRegistry 初始化。
BootstrapRegistry:物件註冊器,作用期間為從應用啟動,Environment 處理直到 ApplicationContext 完備。
ApplicationContextInitializer 列表設定。
ApplicationContextInitializer:回撥介面,用於 Spring ConfigurableApplicationContext 初始化。
通常用於 web 應用 ApplicationContext 自定義初始化。如註冊 property source、啟用 profile 等。
ApplicationListener 列表設定。
ApplicationListener:應用事件監聽介面,基於標準的 EventListener 介面,觀察者模式實現。
main class
public ConfigurableApplicationContext run(String... args) {
long startTime = System.nanoTime();
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
}
listeners.started(context, timeTakenToStartup);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
listeners.ready(context, timeTakenToReady);
}
catch (Throwable ex) {
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
return context;
}
建立,重新整理 ApplicationContext 並執行 Spring 應用。
使用 System.nanoTime(),計算耗時間隔更精確。不可用於獲取具體時刻。
DefaultBootstrapContext = createBootstrapContext();
BootstrapContext:啟動上下文,生命週期同 BootstrapRegistry。
DefaultBootstrapContext 繼承了 BootstrapContext、BootstrapRegistry。
用於 BootstrapRegistry 初始化。
可設定的 ApplicationContext。
SpringApplicationRunListeners = getRunListeners()。
Spring 應用執行期間事件監聽。
listeners.starting():starting step。
ApplicationArguments:提供 SpringApplication 啟動引數存取。
ConfigurableEnvironment = prepareEnvironment()
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach(environment);
listeners.environmentPrepared(bootstrapContext, environment);
DefaultPropertiesPropertySource.moveToEnd(environment);
Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
"Environment prefix cannot be set via properties.");
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
EnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader());
environment = environmentConverter.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
configureEnvironment() 模板方法,代理執行 configurePropertySources() 及 configureProfiles() 方法。
configurePropertySources():PropertySource 設定,用於新增、移除或者調序 PropertySource 資源。CommandLinePropertySource 在這一步處理。
configureProfiles():應用 profile 設定。
ConfigurationPropertySources.attach(environment)
ConfigurationPropertySources:提供對 ConfigurationPropertySource 的存取。
attach(environment):就是將這個功能提供給 environment。
listeners.environmentPrepared(bootstrapContext, environment)
environment-prepared step。
DefaultPropertiesPropertySource.moveToEnd(environment)
DefaultPropertiesPropertySource:是一個 MapPropertySource,包含 SpringApplication 可以使用的一些預設屬性。為了使用方便,預設會置於尾序。
bindToSpringApplication(environment)
將 environment 繫結到 SpringApplication。
Binder:用於物件繫結的容器。
printBanner()。
createApplicationContext()。
內部通過 ApplicationContextFactory 建立。
ApplicationContextFactory:策略介面,預設實現為 DefaultApplicationContextFactory。
為容器設定 ApplicationStartup,用於記錄啟動過程效能指標。
prepareContext()
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);
listeners.contextPrepared(context);
bootstrapContext.close(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 AbstractAutowireCapableBeanFactory) {
((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
}
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));
// 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);
}
設定環境
postProcessApplicationContext() 前置處理
beanNameGenerator 設定,用於 bean 名稱生成。
resourceLoader 設定,用於資源載入。
addConversionService:ConversionService 型別轉換 Service。
applyInitializers()
ApplicationContextInitializer 應用
contextPrepared 事件
【spring.boot.application.context-prepared】step
BootstrapContext 關閉
註冊 springApplicationArguments bean
註冊 springBootBanner bean
AbstractAutowireCapableBeanFactory
設定是否允許 bean 之間的迴圈依賴,並自動處理,預設為 true。
設定是否允許 bean 定義覆蓋,預設為 true。
lazyInitialization 懶載入
設定 LazyInitializationBeanFactoryPostProcessor post-processor。
PropertySource 重排序
設定 PropertySourceOrderingBeanFactoryPostProcessor post-processor。
getAllSources() bean 定義源載入
load() bean 定義載入,BeanDefinitionLoader
用於從底層資源載入 bean 定義資訊,包括 xml、JavaConfig。
是基於 AnnotatedBeanDefinitionReader、XmlBeanDefinitionReader、ClassPathBeanDefinitionScanner 的門面模式。
beanNameGenerator、resourceLoader、environment 設定。
資源載入:
private void load(Object source) {
Assert.notNull(source, "Source must not be null");
if (source instanceof Class<?>) {
load((Class<?>) source);
return;
}
if (source instanceof Resource) {
load((Resource) source);
return;
}
if (source instanceof Package) {
load((Package) source);
return;
}
if (source instanceof CharSequence) {
load((CharSequence) source);
return;
}
throw new IllegalArgumentException("Invalid source type " + source.getClass());
}
contextLoaded() contextLoaded 事件
【spring.boot.application.context-loaded】step。
refreshContext()
註冊 shutdownHook。
Runtime.getRuntime().addShutdownHook(new Thread(this, "SpringApplicationShutdownHook"));
重新整理操作:載入或重新整理
AbstractApplicationContext::refresh()
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
contextRefresh.end();
}
}
}
作為啟動方法,如果失敗,則必須銷燬所有已建立的單例bean。
StartupStep【spring.context.refresh】
準備重新整理 prepareRefresh()
設定啟動日期。
設定 active 標誌。
initPropertySources():子類實現 PropertySource 初始化。
validateRequiredProperties():校驗 ConfigurablePropertyResolver#setRequiredProperties 設定的必需屬性。
obtainFreshBeanFactory():通過子類獲取最新的內部 bean factory。如果存在舊的則先銷燬,然後再建立新的返回。
prepareBeanFactory() 準備 bean factory
setBeanClassLoader():預設為執行緒上下文類載入器,用於 bean 定義載入。
setBeanExpressionResolver() spel 表示式解析設定:StandardBeanExpressionResolver。
addPropertyEditorRegistrar():ResourceEditorRegistrar 用於 bean 建立過程。
新增 ApplicationContextAwareProcessor post-processor。
註冊依賴:BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext。
新增 ApplicationListenerDetector post-processor:用於檢測發現實現了 ApplicationListener 的 bean。
LoadTimeWeaver 處理。
environment、systemProperties、systemEnvironment、applicationStartup 註冊。
postProcessBeanFactory():用於子類實現,修改內部 bean factory。
這一時期,所有的 bean 定義都已被載入,但還未範例化。
StartupStep【spring.context.beans.post-process】
invokeBeanFactoryPostProcessors() 觸發所有已註冊的 BeanFactoryPostProcessor
registerBeanPostProcessors() 註冊 bean post-processor
StartupStep【spring.context.beans.post-process】 結束
initMessageSource() MessageSource 初始化
容器內 bean 名稱:messageSource。
存在則檢查並設定 ParentMessageSource。
不存在則建立預設 DelegatingMessageSource,設定 ParentMessageSource 並註冊。
initApplicationEventMulticaster() 事件分發初始化
容器 bean:applicationEventMulticaster。ApplicationEventMulticaster 介面,用於管理 ApplicationListener,並執行事件分發。
不存在則建立並註冊 SimpleApplicationEventMulticaster 物件。
onRefresh()
用於子類初始化一些特有的 bean。
模板方法,用於重寫實現重新整理邏輯。
registerListeners() 監聽器註冊
將實現了 ApplicationListener 介面的 bean 註冊到容器。
finishBeanFactoryInitialization() 範例化所有餘下的單例 bean。
conversionService。
註冊內嵌值(${...})解析器。
初始化 LoadTimeWeaverAware。
停用型別匹配 ClassLoader。
freezeConfiguration() 凍結所有的 bean 定義。所有註冊的 bean 定義都不允許再有變更。
preInstantiateSingletons() 範例化所有餘下的單例 bean。
ApplicationContext 重新整理完畢後呼叫。
記錄應用啟動資訊。
listeners.started()
包括 ApplicationRunner 和 CommandLineRunner。
listeners.ready()