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启动过程。