springboot 的啓動入口是 SpringApplication run方法,代碼如下:
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
//此處創建 context
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//初始化context 的核心邏輯都在這行代碼裏。
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
再具體分析下 refreshContext的代碼邏輯
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//清除緩存,並讀取配置文件裏的環境變量
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// 此處的 bean factory 是通過父類GenericApplicationContext 初始化的 DefaultListableBeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
// 配置 beanFactory, 包括註冊(第一次) BeanPostProcessor, 設置 classLoader等等。
// BeanPostProcessor 有兩個主要的方法:postProcessBeforeInitialization 和 postProcessAfterInitialization 。
// 這個兩個方法分別的執行時期是 bean 初始化之前和初始化之後。具體的執行時期後面會說到
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
//爲 applicationContext的子類註冊(第二次)個性化的 BeanPostProcessor
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
//執行 context 中註冊的 BeanFactoryPostProcessor中的postProcessBeanFactory() 方法,BeanFactoryPostProcessor只有這一個方法
//BeanFactoryPostProcessor 是 bean 屬性處理容器。即管理 bean工廠中的BeanDefinition,
// BeanDefinition在 spring mvc 中就是 xml 文件中對應的 bean 標籤(注意,是標籤,而不是真實的 JAVA BEAN)。
//可以看到,此處已經 invoke 了postProcessBeanFactory() 方法。 而 BeanPostProcessor 的方法還沒有被調用,
//所以 BeanFactoryPostProcessor的執行是要早於BeanPostProcessor的。
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
//再次註冊BeanPostProcessor(這已經是第三次註冊,
// 第一註冊的是AbstractApplicationContext中用到的 processor,
// 第二次爲ServletWebServerApplicationContext 註冊 processor)。
// 這次是爲實際用到的 context註冊 processor(spring boot 即是AnnotationConfigServletWebServerApplicationContext),
// 併爲根據優先級和 order 排序。
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
// 實例化並註冊 MessageSource類。MessageSource是國際化相關的接口
initMessageSource();
// Initialize event multicaster for this context.
//初始化spring 事件廣播器,ApplicationContext會通過廣播器發送事件,負責監聽廣播器的 listener 會負責處理事件
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
// 在一些特殊的 ApplicationContext子類中實例化一些特殊的 bean.
//例如ServletWebServerApplicationContext(AnnotationConfigServletWebServerApplicationContext的父類)會初始化TomcatWebServer,
//並啓動這個 server,在 spring boot 工程中,相當於啓動了整個 spring boot 項目。
onRefresh();
// Check for listener beans and register them.
//爲ApplicationEventMulticaster註冊監聽 listener(ApplicationListener),
//會有一些默認的 listener被註冊。例如這是一個 dubbo provider的工程,就會註冊DubboBannerApplicationListener
// 同時也會有一些自定義的 listener.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
//終於到了初始 java bean 的階段, 注意此處只初始化單例的 bean, 並且非懶加載的類(默認即非懶加載)。
//雖然此時 java bean已經實例化,但是其依賴自動注入的 bean卻不再此時注入,而是等到用到的時候再去獲取,
//所以這裏不會出現循環依賴的問題。
// 一個 spring bean 的初始化過程如下:
// 1. 執行構造器
// 2. BeanPostProcessor的postProcessBeforeInitialization方法
// 3. InitializingBean的afterPropertiesSet方法
// 4,@Bean註解的initMethod方法
// 5,BeanPostProcessor的postProcessAfterInitialization方法
// 6,DisposableBean的destroy方法
// 7,@Bean註解的destroyMethod方法
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
//實例化LifecycleProcessor並執行其 onRefresh()方法,刷新上下文,啓動一些需要在初始化階段啓動的類(實現了Lifecycle接口的類)
// 發佈ContextRefreshedEvent事件,這個應該是表示上下文啓動完成的事件
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...
//清理單例 bean 的元數據緩存。
resetCommonCaches();
}
}
}
至此, spring boot的啓動過程就完成了, 基於篇幅和時間問題。其中還有很多代碼細節沒有仔細分析,這些就留給未來吧。
整個過程分析下來發現這個啓動過程會有幾個核心接口(應該也是 spring 整個 ioc機制的核心接口)
BeanFactory
ApplicationContext
BeanPostProcessor
BeanFactoryPostProcessor
ApplicationEventMulticaster
BeanDefinition
LifecycleProcessor
以及每個接口裏面的方法及其執行時序。
弄清楚每一個接口的原理和具體使用場景,對我們使用和理解 spring 至關重要。