springboot的完整启动流程
文章目录
- springboot的完整启动流程
-
-
- eg:
- 计时
- 接着创建引导上下文(Context环境)
-
- 进入createBootstrapContext()中查看源代码:
- 让当前应用进入headless模式
- 获取所有运行监听器(为了方便所有Listener进行事件感知)
- listeners.starting,遍历所有监听器,并且starting
- 进入try中的执行
-
- 首先是保存命令行中所有的参数
- 准备环境信息
-
- 总结准备环境信息
- 配置需要忽略的环境信息
- 打印banner
- 创建IOC容器!
-
- 步入createApplicationContext
- 记录当前事件
- 准备IOC容器信息(准备ApplicationContext)
- 刷新IOC容器
- 容器刷新后
- listener通知项目启动
- 调用所有的runners
- 异常处理
- Running方法
- 创建结束
-
eg:
书接 springboot初始化
上文讲述了具体的spring的初始化流程,接下来就是从run方法开始讲述完整的springboot2的启动流程,版本是2.6.4
计时
在将启动器,引导器,初始化器保存和确定了主类之后,返回最准确的可用系统计时器的当前值,以毫微秒为单位。
long startTime = System.nanoTime();
接着创建引导上下文(Context环境)
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
进入createBootstrapContext()中查看源代码:
private DefaultBootstrapContext createBootstrapContext() {
DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));
return bootstrapContext;
}
-
首先创建DefaultBootstrapContext对象,保存信息。
-
接着获取之前所有的initializer并执行initialize(bootstrapContext)),来完成对引导启动器的环境设置
让当前应用进入headless模式
java.awt.headless
configureHeadlessProperty();
private void configureHeadlessProperty() {
System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
}
获取所有运行监听器(为了方便所有Listener进行事件感知)
SpringApplicationRunListeners listeners = getRunListeners(args);
- 获取运行监听器的具体方法
- 源代码中依然是getSpringFactoriesInstances,从spring.factories中寻找SpringApplicationRunListener.class
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),
this.applicationStartup);
}
listeners.starting,遍历所有监听器,并且starting
doWithListeners中的foreach方法。
也相当于通知所有感兴趣(需要这个信息)系统正在启动的“人”,项目正在starting
void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),
(step) -> {
if (mainApplicationClass != null) {
step.tag("mainApplicationClass", mainApplicationClass.getName());
}
});
}
/**
进入doWithListeners
*/
private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction,
Consumer<StartupStep> stepAction) {
StartupStep step = this.applicationStartup.start(stepName);
this.listeners.forEach(listenerAction);
if (stepAction != null) {
stepAction.accept(step);
}
step.end();
}
进入try中的执行
首先是保存命令行中所有的参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
准备环境信息
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
//方法体👇
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
// Create and configure the environment,有环境信息就获取=
ConfigurableEnvironment environment = getOrCreateEnvironment();
//getOrCreateEnvironment,返回或创建基础环境信息对象
configureEnvironment(environment, applicationArguments.getSourceArgs());
//配置环境,通过命令行参数和环境信息
ConfigurationPropertySources.attach(environment);
//绑定信息,也就是保存工作
listeners.environmentPrepared(bootstrapContext, environment);
//listeners就是之前获取到的所有的RunListener,通知所有监听器当前环境准备完成
DefaultPropertiesPropertySource.moveToEnd(environment);
Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
"Environment prefix cannot be set via properties.");
bindToSpringApplication(environment);
//绑定工作
if (!this.isCustomEnvironment) {
environment = convertEnvironment(environment);
}
ConfigurationPropertySources.attach(environment);
return environment;
}
- 而在配置环境信息时:在更深层的调用方法configurePropertySources中有MutablePropertySources sources=environment.getPropertySources();能够获取@PropertySource,读取到外部的配置文件,也就是说此方法加载全系统中所有的配置信息!
- 而在之后,如果有命令行中的信息也会添加进配置中
总结准备环境信息
-
读取所有配置源的配置属性值
configurePropertySources -
通知
监听器调用listeners.environmentPrepared(bootstrapContext, environment);通知所有监听器当前环境准备完成 -
绑定环境信息
配置需要忽略的环境信息
configureIgnoreBeanInfo(environment);
打印banner
Banner printedBanner = printBanner(environment);
创建IOC容器!
context = createApplicationContext();
步入createApplicationContext
protected ConfigurableApplicationContext createApplicationContext() {
return this.applicationContextFactory.create(this.webApplicationType);
}
根据当前项目类型(Servlet)创建
当前则会创建AnnotationConfigServletWebServerApplicationContext();
记录当前事件
context.setApplicationStartup(this.applicationStartup);
准备IOC容器信息(准备ApplicationContext)
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
- 进入prepareContext
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
//设置环境
postProcessApplicationContext(context);
//保存基本环境信息
applyInitializers(context);
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 AbstractAutowireCapableBeanFactory) {
((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
}
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// 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);
}
-
保存基本环境信息
context.setEnvironment(environment); -
IOC容器的后置处理流程
postProcessApplicationContext(context);
像注册一些组件,读取配置文件的资源,资源的加载器 -
应用初始化器applyInitializers(context);
遍历所有的ApplicationContextInitializer,调用initialize(context);来对IOC容器进行初始化(扩展工作)
也就说之前保存的ApplicationContextInitializer在此时调用了。 -
遍历所有的Listener调用contextPrepared(context);
通知所有的监听器
至此,IOC容器的上下文配置完毕。 -
之后就是关闭bootstrapContext.close(context);
-
然后日志信息
-
拿到Bean工厂,注册单实例
(项目中的参数会作为组件注册进去)
banner也是IOC容器中的一个组件 -
所有监听器调用contextLoaded
通知IOC容器已经加载完毕 -
准备工作完毕
刷新IOC容器
- 跟随断点进入代码中
private void refreshContext(ConfigurableApplicationContext context) {
if (this.registerShutdownHook) {
shutdownHook.registerApplicationContext(context);
}
refresh(context);
}
注册钩子,接下来进入spring‘的核心源码refresh!
调用IOC容器的refresh
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
// Prepare this context for refreshing.
//为刷新准备上下文。
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
//告诉子类刷新内部bean工厂。
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
//准备bean工厂在这个上下文中使用。
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
//允许在context子类中对bean工厂进行后处理。
postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
// Invoke factory processors registered as beans in the context.
//调用在上下文中注册为bean的工厂处理器
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
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...
resetCommonCaches();
contextRefresh.end();
}
}
}
在源码中有英语注释此处便不再过多赘述,深入源码改日深追!
容器刷新后
afterRefresh(context, applicationArguments);
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
- 监听容器启动花费了多长时间
listener通知项目启动
调用所有的runners
callRunners(context, applicationArguments);
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<>();
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);
for (Object runner : new LinkedHashSet<>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}
- 获取容器中的Runner分别是
ApplicationRunner
CommandLineRunner
合并所有Runner并且按照@Order(优先级)进行排序
遍历所有的Runner调用run方法
异常处理
- 调用Listener的failed方法
Running方法
- 通知所有监听器的running方法,如果中间有异常,仍然会调用所有监听器的failed方法
running方法结束后,返回整个IOC容器。SpringBoot启动结束。