SpringBoot啟動過程原理
1.1 Springboot啟動:
@SpringBootApplication
public class ServerApplication {
public static void main(String[] args) {
SpringApplication.run(ServerApplication.class,args);
}
}
從上面程式碼看,呼叫了SpringApplication的靜態方法run。這個run方法會構造一個SpringApplication的例項,然後再呼叫這裡例項的run方法就表示啟動SpringBoot。具體物件處理流程看下邊時序圖:
概述:
- 構造SpringApplication的例項(時序圖步驟1-2)
- 呼叫SpringApplication.run()方法(時序圖步驟3)
- 構造SpringApplicationRunListeners 例項(時序圖步驟3.1.1)
- 釋出ApplicationStartedEvent事件(時序圖步驟3.1.2)
- SpringApplicationRunListeners 例項準備環境資訊(時序圖步驟3.1.3)
- 建立ApplicationContext物件(時序圖步驟3.1.4)
- ApplicationContext例項準備環境資訊(時序圖步驟3.1.5)
- 重新整理的上下文(時序圖步驟3.1.6)
注:文章按照該順序講解【1.2 啟動載入過程分析】
時序圖:
1.2 啟動載入過程分析
1.2.1 構造SpringApplication的例項(時序圖步驟1-2)
程式碼
public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
// 步驟1
return new SpringApplication(sources).run(args);
}
public SpringApplication(Object... sources) {
// 步驟1.1
initialize(sources);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private void initialize(Object[] sources) {
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
this.webEnvironment = deduceWebEnvironment();
//載入META-INF/spring.factories路徑ApplicationContextInitializer.class
getSpringFactoriesInstances(
ApplicationContextInitializer.class));
setListeners((Collection)
//載入META-INF/spring.factories路徑ApplicationListener.class
getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
分析
⑴.通過ClassLoader.getResources載入META-INF/spring.factories路徑下的
檔案資訊,從中找key為ApplicationContextInitializer.class,並例項化。
⑵.通過ClassLoader.getResources載入META-INF/spring.factories路徑下的
檔案資訊ApplicationListener.class對應類,並例項化。
1.2.2 呼叫SpringApplication.run()方法(時序圖步驟3)
程式碼:
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
configureHeadlessProperty();
// 步驟3.1.1
SpringApplicationRunListeners listeners = getRunListeners(args);
// 步驟3.1.2
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
// 步驟 3.1.3
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
Banner printedBanner = printBanner(environment);
// 步驟3.1.4
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
// 步驟3.1.5
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
// 步驟3.1.6
refreshContext(context);
// 步驟3.1.7
afterRefresh(context, applicationArguments);
// 步驟3.1.8
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}
1.2.2 步驟3.1.1:
程式碼
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
// (1)
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
SpringApplicationRunListener.class, types, this, args));
}
分析
(1). 通過ClassLoader.getResources載入META-INF/spring.factories路徑下的
檔案資訊,從中找key為SpringApplicationRunListener對應類,並例項化。
1.2.3 步驟3.1.2:
程式碼
public void starting() {
for (SpringApplicationRunListener listener : this.listeners) {
listener.starting();
}
}
@Override
@SuppressWarnings("deprecation")
public void starting() {
this.initialMulticaster
.multicastEvent(new ApplicationStartedEvent(this.application, this.args));
}
分析
釋出ApplicationStartedEvent事件。
1.2.4 步驟3.1.3:
程式碼
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
// ⑴. 得到環境物件ConfigurableEnvironment
ConfigurableEnvironment environment = getOrCreateEnvironment();
// ⑵. 並配置環境資訊;對listeners初始化環境屬性
configureEnvironment(environment, applicationArguments.getSourceArgs());
// ⑶. 釋出ApplicationEnvironmentPreparedEvent事件。
listeners.environmentPrepared(environment);
if (isWebEnvironment(environment) && !this.webEnvironment) {
environment = convertToStandardEnvironment(environment);
}
return environment;
}
分析
⑴. 得到環境物件ConfigurableEnvironment
⑵. 並配置環境資訊;對listeners初始化環境屬性。
⑶. 釋出ApplicationEnvironmentPreparedEvent事件。
步驟3.1.4:
分析
建立ApplicationContext物件 ,其中在例項化ApplicationContext子類
AnnotationConfigApplicationContext時,如程式碼:
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
會建立AnnotatedBeanDefinitionReader物件檢測是否需要將一下物件放到Spring上下文中
// 使用者配置Configuration註解,實現了BeanDefinitionRegistryPostProcessor介面
ConfigurationClassPostProcessor
// 用於配置Autowired註解,實現了MergedBeanDefinitionPostProcessor介面
AutowiredAnnotationBeanPostProcessor
// 用於配置Required註解,實現了MergedBeanDefinitionPostProcessor介面
RequiredAnnotationBeanPostProcessor
// 用於配置JSR-250註解,實現了InstantiationAwareBeanPostProcessor介面
CommonAnnotationBeanPostProcessor
// 用於配置JPA註解
PersistenceAnnotationBeanPostProcessor
// 用於配置EventListener註解,實現了SmartInitializingSingleton介面
EventListenerMethodProcessor
// EventListener工廠
DefaultEventListenerFactory
步驟3.1.5:
程式碼
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
// ⑴.對ApplicationContext設定環境變數;
context.setEnvironment(environment);
// ⑵.配置屬性ResourceLoader和ClassLoader屬性;
postProcessApplicationContext(context);
// ⑶.迴圈初始化繼承了
applyInitializers(context);
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
// Load the sources
Set<Object> sources = getSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[sources.size()]));
listeners.contextLoaded(context);
}
分析:
⑴.對ApplicationContext設定環境變數;
⑵.配置屬性ResourceLoader和ClassLoader屬性;
⑶.呼叫步驟1查詢出來ApplicationContextInitializer子類,迴圈呼叫initialize()方法。
@SuppressWarnings({ "rawtypes", "unchecked" })
protected void applyInitializers(ConfigurableApplicationContext context) {
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
initializer.getClass(), ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
initializer.initialize(context);
}
}
⑷.釋出ApplicationPreparedEvent事件。
步驟3.1.6
程式碼:
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// ⑴.準備重新整理的上下文環境
prepareRefresh();
// ⑵.初始化BeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// ⑶.對BeanFactory進行各種功能填充
prepareBeanFactory(beanFactory);
try {
// ⑷.子類覆蓋方法做額外的處理
postProcessBeanFactory(beanFactory);
// ⑸.啟用各種BeanFactory處理器
invokeBeanFactoryPostProcessors(beanFactory);
// ⑹.註冊攔截Bean建立的Bean處理,這裡只是註冊,真正呼叫是再拿去Bean的時候
registerBeanPostProcessors(beanFactory);
// ⑺.為上下文初始化Message源,即不同語言的訊息體,國際化處理
initMessageSource();
// ⑻.初始化應用訊息廣播器,並放到applicationEventMulticaster bean中
initApplicationEventMulticaster();
// ⑼.留給子類來初始化其他bean
onRefresh();
// ⑽.在所有註冊的bean中查詢Listener bean,註冊到訊息廣播中
registerListeners();
// ⑾.初始化剩下的單例項(非惰性)
finishBeanFactoryInitialization(beanFactory);
// ⑿.完成重新整理過程,通知生命週期處理器lifecycleProcessor重新整理過程,同時發出ContextRefreshEvent通知別人
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();
}
}
}
分析:
⑴.準備重新整理的上下文環境
⑵.初始化BeanFactory
⑶.對BeanFactory進行各種功能填充
⑷.子類覆蓋方法做額外的處理
⑸.啟用各種BeanFactory處理器
⑹.註冊攔截Bean建立的Bean處理,這裡只是註冊,真正呼叫是再拿去Bean的時候
⑺.為上下文初始化Message源,即不同語言的訊息體,國際化處理
⑻.初始化應用訊息廣播器,並放到applicationEventMulticaster bean中
⑼.留給子類來初始化其他bean
⑽.在所有註冊的bean中查詢Listener bean,註冊到訊息廣播中
⑾.初始化剩下的單例項(非惰性)
⑿.完成重新整理過程,通知生命週期處理器lifecycleProcessor重新整理過程,同時發出ContextRefreshEvent通知別人