SpringBoot之啓動容器源碼分析
1、SpringApplication#run()
由SpringBoot應用引導類的 SpringApplication#run() 進入我們可以看到以下代碼
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
// 監視器啓動
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
this.configureHeadlessProperty();
// 從 META-INF/spring.factories 中獲取 SpringApplicationRunListener 實現類,並調用starting()
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting();
Collection exceptionReporters;
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 準備環境變量配置
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
// 通過 spring.beaninfo.ignore 配置是否忽略bean信息 暫不明覺厲
this.configureIgnoreBeanInfo(environment);
// 打印SpringBoot控制檯啓動圖案
Banner printedBanner = this.printBanner(environment);
// 創建應用上下文
context = this.createApplicationContext();
// 從 META-INF/spring.factories 中獲取異常報告處理器,用作處理啓動異常
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
/**
* 準備應用上下文
* 1 設置上下文環境配置
* 2 註冊 beanNameGenerator 等
* 3 執行 ApplicationContextInitializer#initialize()初始化
*/
ApplicationContextInitializer#initialize() 初始化
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 刷新上下文(下面重點分析)
this.refreshContext(context);
// 容器初始化之後 開始執行 ApplicationRunner 和 CommandLineRunner 自定義初始化執行器
this.afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
listeners.started(context);
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}
try {
listeners.running(context);
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
2、SpringBoot 啓動源碼之 refreshContext() 方法
通過上面的代碼可以看出,關鍵代碼在於
this.refreshContext(context)
該方法最終會執行
AbstractApplicationContext#refresh()
這纔是Spring容器啓動的核心內容,重頭戲一起往下看:
- spring容器初始化總覽 AbstractApplicationContext#refresh()
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
// 準備初始化容器工作,設置啓動標誌、記錄啓動時間等
this.prepareRefresh();
// 創建 beanFactory, 並加載bean定義等
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
// beanFactory注入一些標準組件,例如ApplicationContextAwareProcessor,ClassLoader等
this.prepareBeanFactory(beanFactory);
try {
// 給實現類留的一個鉤子,例如注入BeanPostProcessors,這裏是個空方法
this.postProcessBeanFactory(beanFactory);
// 執行 BeanFactoryPostProcessor 實現類的 postProcessBeanFactory()方法
this.invokeBeanFactoryPostProcessors(beanFactory);
// 註冊 BeanPostProcessor 實現類
this.registerBeanPostProcessors(beanFactory);
// 國際化資源處理
this.initMessageSource();
// bean工廠註冊一個key爲applicationEventMulticaster的廣播器 用於事件廣播
this.initApplicationEventMulticaster();
// 給實現類留的一鉤子,可以執行其他refresh的工作,比如啓動tomcat server
this.onRefresh();
// 註冊事件監聽器
this.registerListeners();
// 完成bean的初始化
this.finishBeanFactoryInitialization(beanFactory);
// 完成容器啓動,發佈容器啓動事件
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
上述即spring容器啓動流程總覽,不建議大家閱讀源碼每一行代碼都需要看懂,細看的話只會讓你陷入到無窮無盡的代碼海洋中。我們需要學會擇重避輕,下面我將重點分析bean初始化流程。
3、Spring bean的加載
由上述源碼我們可以看出bean的加載核心代碼在於
this.finishBeanFactoryInitialization(beanFactory);
下面一起來分析以下該方法的實現,以下直接上關鍵代碼:bean的三級緩存,以及bean的初始化
/**
* finishBeanFactoryInitialization() 最終會調用該方法
*/
public void preInstantiateSingletons() throws BeansException {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Pre-instantiating singletons in " + this);
}
List<String> beanNames = new ArrayList(this.beanDefinitionNames);
Iterator var2 = beanNames.iterator();
while(true) {
String beanName;
Object bean;
do {
while(true) {
RootBeanDefinition bd;
do {
do {
do {
if (!var2.hasNext()) {
var2 = beanNames.iterator();
while(var2.hasNext()) {
beanName = (String)var2.next();
// 這裏是從 bean的三級緩存中取
Object singletonInstance = this.getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton)singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(() -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, this.getAccessControlContext());
} else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
return;
}
beanName = (String)var2.next();
bd = this.getMergedLocalBeanDefinition(beanName);
} while(bd.isAbstract());
} while(!bd.isSingleton());
} while(bd.isLazyInit());
if (this.isFactoryBean(beanName)) {
bean = this.getBean("&" + beanName);
break;
}
this.getBean(beanName);
}
} while(!(bean instanceof FactoryBean));
FactoryBean<?> factory = (FactoryBean)bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
SmartFactoryBean var10000 = (SmartFactoryBean)factory;
((SmartFactoryBean)factory).getClass();
isEagerInit = (Boolean)AccessController.doPrivileged(var10000::isEagerInit, this.getAccessControlContext());
} else {
isEagerInit = factory instanceof SmartFactoryBean && ((SmartFactoryBean)factory).isEagerInit();
}
if (isEagerInit) {
this.getBean(beanName);
}
}
}
上面代碼可以看出首先 從bean的三級緩存中獲取bean,如緩存中沒有,則調用getBean()
Bean的三級緩存
singletonObjects:用於存放完全初始化好的 bean,從該緩存中取出的 bean 可以直接使用
earlySingletonObjects:提前曝光的單例對象的cache,存放原始的 bean 對象(尚未填充屬性),用於解決循環依賴
singletonFactories:單例對象工廠的cache,存放 bean 工廠對象,用於解決循環依賴
/**
* 從三級緩存中獲取bean
*/
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
synchronized(this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
下面看getBean() 方法調用如下
1、getBean()
2、doGetBean()
3、createBean()
4、doCreateBean()
5、populateBean()
6、initializeBean()
以上看出獲取bean還是很曲折的,我們直接關注最後 initializeBean()
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
// 執行 Aware 接口
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(() -> {
this.invokeAwareMethods(beanName, bean);
return null;
}, this.getAccessControlContext());
} else {
this.invokeAwareMethods(beanName, bean);
}
/**
* 執行 BeanPostProcessor#postProcessBeforeInitialization bean初始化前置方法
* 其中 InitDestroyAnnotationBeanPostProcessor 來執行 @PostConstruct 標註的方法
*/
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
}
try {
// bean初始化方法 init-method 和 InitializingBean#afterPropertiesSet()
this.invokeInitMethods(beanName, wrappedBean, mbd);
} catch (Throwable var6) {
throw new BeanCreationException(mbd != null ? mbd.getResourceDescription() : null, beanName, "Invocation of init method failed", var6);
}
/**
* 執行 BeanPostProcessor#postProcessAfterInitialization bean初始化後置方法
* 其中 InitDestroyAnnotationBeanPostProcessor 來執行 @PreDestroy 標註的方法
*/
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
到此我們已經分析完SpringBoot啓動過程。