SpringBoot启动流程简析
SpingBoot 启动过程
阶段一:SpringApplication 构造
- 记录 BeanDefinition 源
- 推断应用类型
- 记录 ApplicationContext 初始化器
- 记录监听器
- 推断主启动类
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
// 记录 BeanDefinition 源,也就是我们的启动类的全限定类名
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 推断应用类型 共三种类型: REACTIVE、NONE、SERVLET
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 记录 ApplicationContext 初始化器
this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 记录监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 推断主启动类,也就是main方法所在类的全限定类名
this.mainApplicationClass = deduceMainApplicationClass();
}
阶段二:执行 run 方法
-
得到 SpringApplicationRunListeners,名字取得不好,实际是事件发布器
- 发布 application starting 事件1️⃣
-
封装启动 args
-
准备 Environment 添加命令行参数(*)
-
ConfigurationPropertySources 处理(*)
- 发布 application environment 已准备事件2️⃣
-
通过 EnvironmentPostProcessorApplicationListener 进行 env 后处理(*)
- application.properties,由 StandardConfigDataLocationResolver 解析
- spring.application.json
-
绑定 spring.main 到 SpringApplication 对象(*)
-
打印 banner(*)
-
创建容器
-
准备容器
- 发布 application context 已初始化事件3️⃣
-
加载 bean 定义
- 发布 application prepared 事件4️⃣
-
refresh 容器
- 发布 application started 事件5️⃣
-
执行 runner
-
发布 application ready 事件6️⃣
-
这其中有异常,发布 application failed 事件7️⃣
-
public ConfigurableApplicationContext run(String... args) {
// 用来计算springboot启动花了多长时间
StopWatch stopWatch = new StopWatch();
stopWatch.start();
//
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
configureHeadlessProperty();
// 读取spring.factories获取一个事件发布器
SpringApplicationRunListeners listeners = getRunListeners(args);
// 发布 application starting 事件1️⃣ (表示springboot开始启动了)
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
// 封装args,将args分为选项参数和非选项参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// prepareEnvironment:见下面的详细解读
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
configureIgnoreBeanInfo(environment);
// 打印Banner信息
Banner printedBanner = printBanner(environment);
// 根据在SpringApplication构造方法中判断的容器类型去创建Spring容器
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
// prepareContext:见下面的详细解读
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// refresh 容器:见下面的详细解读 调用applicationConetext.redresh方法,bean的生命周期,调用bean的后处理器等等
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
// 发布 application started 事件5️⃣
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
// 出现异常会在这里返回
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
// 启动成功事件
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
return context;
}
prepareEnvironment方法
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
// 生成environment,并添加一个基于命令行的源
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 解析properties中的-、_等分隔符,统一使用 -
ConfigurationPropertySources.attach(environment);
// 通过事件的发布,为environment提供更多的源,例如System源、random源、yml或properties源 发布 application environment 已准备事件2️⃣
listeners.environmentPrepared(bootstrapContext, environment);
DefaultPropertiesPropertySource.moveToEnd(environment);
Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
"Environment prefix cannot be set via properties.");
// 将environment中已spring.main打头的和SpringApplication做一个绑定
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
prepareContext方法
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
// 准备容器 发布 application context 已初始化事件3️⃣
applyInitializers(context);
// 加载 bean 定义 发布 application prepared 事件4️⃣
listeners.contextPrepared(context);
bootstrapContext.close(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);
}
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// Load the sources
// 得到所有的源,也就是 [class com.netft.Application]
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
// 加载BeanDefinitionLoader
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}
((AbstractApplicationContext) applicationContext).refresh();方法
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 准备此上下文以进行刷新。
prepareRefresh();
// 告诉子类刷新内部bean工厂。
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 准备bean工厂以便在此上下文中使用。
prepareBeanFactory(beanFactory);
try {
// 允许在上下文子类中对bean工厂进行后处理。
postProcessBeanFactory(beanFactory);
// 调用在上下文中注册为bean的工厂处理器。
invokeBeanFactoryPostProcessors(beanFactory);
// 注册拦截bean创建的bean处理器。
registerBeanPostProcessors(beanFactory);
// 初始化此上下文的消息源。
initMessageSource();
// 为此上下文初始化事件多播。
initApplicationEventMulticaster();
// 初始化特定上下文子类中的其他特殊bean。
onRefresh();
// 检查侦听器bean并注册它们。
registerListeners();
// 实例化所有剩余的(非惰性初始化)单例。包括我们自己写的一些bean
finishBeanFactoryInitialization(beanFactory);
// 最后一步:发布相应的事件。
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 销毁已创建的单例以避免悬空资源。
destroyBeans();
// 重置“活动”标志。
cancelRefresh(ex);
// 将异常传播到调用方。
throw ex;
}
finally {
//重置Spring核心中的常见自省缓存,因为我们可能不再需要单例bean的元数据。。。
resetCommonCaches();
}
}
}