SpringBoot 启动流程源码分析
首先需要了解一下SpringBoot的启动流程,创建SpringApplication
的构造方法主要逻辑为指定了容器类型,并且使用ClassLoad加载META-INF/spring.factories
下配置的一个应用启动监听器和一个上下文监听器,如果没有配置文件META-INF/spring.factories
,那么返回空的List集合。
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();
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
再来追踪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 = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
④
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
⑤
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;
}
-
获取事件监听器SpringApplicationRunListener,并且启动监听器,播报启动事件
-
准备环境,执行environmentPrepared()方法播报事件,被
ConfigFileApplicationListener
监听处理。
读取配置项
spring.profiles.active
,用于构建ActiveProfiles
,同时绑定一系列转换器,用于解析配置文件中的值。public static void addApplicationConverters(ConverterRegistry registry) { addDelimitedStringConverters(registry); registry.addConverter(new StringToDurationConverter()); registry.addConverter(new DurationToStringConverter()); registry.addConverter(new NumberToDurationConverter()); registry.addConverter(new DurationToNumberConverter()); registry.addConverter(new StringToDataSizeConverter()); registry.addConverter(new NumberToDataSizeConverter()); registry.addConverterFactory(new StringToEnumIgnoringCaseConverterFactory()); }
同时在SpringBoot2.0版本后增加了对
@ConfigurationProperties
支持。把ConfigurationPropertySource
绑定在environment
内部.ConfigFileApplicationListener
监听处理主要是使用ClassLoad
加载META-INF/spring.factories
下配置的EnvironmentPostProcessor
.然后把当前类也加入返回集合内,在ConfigFileApplicationListener#postProcessEnvironment
时把配置文件内配置项,转换在尾插法添加到propertySourceList中。protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) { RandomValuePropertySource.addToEnvironment(environment); new Loader(environment, resourceLoader).load(); } public void load() { this.profiles = new LinkedList<>(); this.processedProfiles = new LinkedList<>(); this.activatedProfiles = false; this.loaded = new LinkedHashMap<>(); initializeProfiles(); while (!this.profiles.isEmpty()) { Profile profile = this.profiles.poll(); if (profile != null && !profile.isDefaultProfile()) { addProfileToEnvironment(profile.getName()); } load(profile, this::getPositiveProfileFilter, addToLoaded(MutablePropertySources::addLast, false)); this.processedProfiles.add(profile); } resetEnvironmentProfiles(this.processedProfiles); load(null, this::getNegativeProfileFilter, addToLoaded(MutablePropertySources::addFirst, true)); addLoadedPropertySources(); }
- 创建上下文,根据项目类型创建上下文
protected ConfigurableApplicationContext createApplicationContext() { Class<?> contextClass = this.applicationContextClass; if (contextClass == null) { try { switch (this.webApplicationType) { case SERVLET: contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS); break; case REACTIVE: contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS); break; default: contextClass = Class.forName(DEFAULT_CONTEXT_CLASS); } } catch (ClassNotFoundException ex) { throw new IllegalStateException( "Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass", ex); } } return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass); }
创建上下文对象,针对
SERVLET
项目,创建的上下文为AnnotationConfigServletWebServerApplicationContext
对象,该类支持
@Configuration
,org.springframework.stereotype
的注解.
- 准备上下文,执行完成后调用
contextPrepared
方法,contextLoaded
方法
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { context.setEnvironment(environment); postProcessApplicationContext(context); applyInitializers(context); listeners.contextPrepared(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 DefaultListableBeanFactory) { ((DefaultListableBeanFactory) beanFactory) .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } // 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); }
绑定
environment
到当前context,同时在上下文中指定Resource,和Bean名称的默认生成类,以及绑定转换器。触发
ApplicationContextInitializer#initialize
的执行播报容器上下文启动事件
日志打印入口类信息和当前的active profile
添加一些特殊的bean注册在当前上下文。
播报上下文准备完毕事件
- spring容器启动,去扫描并且初始化单例bean
代码直接看
AbstractApplicationContext#refresh
public void refresh() throws BeansException, IllegalStateException { synchronized(this.startupShutdownMonitor) { //这里会设置Context的启动时间,以及校验配置项的正确性和是否缺失配置项 this.prepareRefresh(); //获取创建上下文时候建立的 ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory(); //填充BeanFactory,设定转换器,解析器,类加载器等. // 这里提前注册一个用于检测ApplicationListener接口实现类的Bean是否是单例的后置处理器 this.prepareBeanFactory(beanFactory); try { 1. this.postProcessBeanFactory(beanFactory); 2. this.invokeBeanFactoryPostProcessors(beanFactory); 3. this.registerBeanPostProcessors(beanFactory); 4. this.initMessageSource(); 5. this.initApplicationEventMulticaster(); 6. this.onRefresh(); this.registerListeners(); 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(); } } }
- 扫描添加默认的
BeanFactoryPostProcessor
的后置处理器的并执行postProcessBeanFactory
方法- 加载工程中的所有的
BeanFactoryPostProcessor
的子类。按照@Order
排序,反之无序执行。最终调用invokeBeanFactoryPostProcessors
触发所有实现类的postProcessBeanFactory
方法的执行。所有后置处理器的执行顺序的implement PriorityOrdered.
>implement Ordered.
> 无序。- 处理实现BeanPostProcessor接口的处理器。和上面工厂方式的一样。
- 初始化
MessageSource
的对象- 初始化
ApplicationEventMulticaster
对象- 用于特殊子类上下文重写去处理特殊性Bean,例如UiApplicationContext则是用来处理对应的
themeSource
的Bean- 添加实现
ApplicationListener
的类,加载到监听器内。并且如果配置了容器启动播报事件,则触发一次播报。- 实例化所有的非懒加载的Bean.
配置转换Bean
添加value解析器(内嵌的Bean后置处理器),Resolve $ placeholders in the given text,
提前初始化
LoadTimeWeaverAware
,用来提前注册对应的的转换器。初始化bean参见
org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons
方法处理所有的非抽象,非懒加载的单例bean和工厂bean。
在getBean方法就是闻名遐迩的IOC,
首选去获取单例对象,这里提到二级缓存
如果该对象已存在,则要去判断
circular reference
判断bean工厂中是否有该bean
执行到此标记Bean被创建
初始化当前bean所依赖的bean
针对生命周期,创建单例bean或者是原型模式创建bean
比较创建的bean对象和Class是否一致。不一致通过调用
TypeConverter
来处理
-
执行程序入口类覆盖的
afterRefresh
方法。如果没有重写则跳过 -
执行
ApplicationRunListeners
中的started
方法,执行ApplicationRunner
和CommandLineRunner
如果需要在
Spring Bean
初始化之后执行需要执行特定的动作,可以利用ApplicationRunner接口 或者 CommandLineRunner接口,这俩个接口的实现类型执行顺序在没有指定@Order
的时候,默认自然排序,反之按照@Order
的值从小到大执行。
SpringBoot的启动流程如上所示,今日突然考虑到对于IOC三级缓存的一点理解,懒得另开篇。就在此地赘述一番!
为什么是三级缓存,二级就完事的事情为何还要多添步骤?
在spring解决循环依赖的过程:一级缓存singletonObject
存完整的的Bean,二级缓存earlySingletonObject
存储未完成全部注入的Bean,就是那些当出现循环依赖时可以先注入earlySingletonObject中的Bean实例。三级缓存singletonFactory
存对应bean的工厂对象 ObjectFactory
,看最新代码这里已经改成了函数式接口执行addSingletonFactory
方法,来往singletonFactory添加ObjectFactory
的匿名内部类中,具体的执行方法为getEarlyBeanReference
this.addSingletonFactory(beanName, () -> {
return this.getEarlyBeanReference(beanName, mbd, bean);
});
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (bean != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
if (exposedObject == null) {
return exposedObject;
}
}
}
}
return exposedObject;
}
hasInstantiationAwareBeanPostProcessors()
这里证明预留了一个扩展点用于执行InstantiationAwareBeanPostProcessor
后置处理器的扩展点,允许在对象返回之前修改甚至替换bean,这里就是IOC和AOP的交汇点。由此来看:如果存在AOP代理Proxy,singletonFactory返回的不是原始的Bean实例,而是实现AOP方法的Proxy。
在研究Spring事务的章节就理清楚了,Spring结合AOP跟Bean的生命周期本身就是通过AnnotationAwareAspectJAutoProxyCreator
这个bean后置处理器来完成的,在这个后置处理的postProcessAfterInitialization方法中对初始化后的Bean完成AOP代理。如果出现了循环依赖,那没有办法,只有给Bean先创建代理,但是没有出现循环依赖的情况下,设计之初就是让Bean在生命周期的最后一步完成代理而不是在实例化后就立马完成代理。
- 存在AOP的情况
singletonFactory
暴露ObjectFactory目的是为了完成AOP代理。对象工厂清楚如何创建对象的AOP代理,但是不会立马创建,而是到合适的时机进行AOP代理对象的创建。
earlySingletonObject
存在的目的之一是保证对象只有一次AOP代理。当调用三级缓存的getObject()方法返回的对象会存入二级缓存,这样,当接下来的依赖者调用的时候, 会先判断二级缓存是否有目标对象,如果存在直接返回。
- 不存在AOP的情况
singletonFactory
直接粗暴就是为了暴露ObjectFactory为了完成对象的实例化。earlySingletonObject
:用于存放半成品的循环依赖bean。
所以 三级缓存的存在 既解决了单例的循环依赖,同时提供了AOP代理的支持。