大家都知道springboot的启动是通过一个main函数执行一个
SpringApplication.run(*.class, args); 来启动整个项目的。今天我想整理一下SpringApplication.run的启动流程便于自己日后的学习。
本文以spring-boot-starter-parent 2.5.2版本为例分析
1.首先创建一个StopWatch对象用于发布一个开始事件,此类主要是用于统计任务的运行时间的
2.创建 DefaultBootstrapContext实例
private DefaultBootstrapContext createBootstrapContext() {
DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();//创建 DefaultBootstrapContext实例
this.bootstrapRegistryInitializers.forEach((initializer) -> //遍历注册表初始化器
initializer.initialize(bootstrapContext));//每个注册表初始器初始化上下文
return bootstrapContext;
}
bootstrapRegistryInitializers是通过getBootstrapRegistryInitializersFromSpringFactories()
实质上是通过SpringFactoriesLoader的loadSpringFactories方法遍历整个ClassLoader中所有jar包下的META-INF包下spring.factories文件的初始化配置。
3.configureHeadlessProperty(); 设置java.awt.headless为true表示运行在服务器器端,在没有显示器器和鼠标键盘的模式下工作,模拟 输入输出设备功能。
4.SpringApplicationRunListeners listeners = getRunListeners(args);//创建所有 Spring 运行监听器并发布应用启动事件(获取spring-boot jar包META-INF下spring.factories下SpringApplicationRunListener的配置
listeners.starting(bootstrapContext, this.mainApplicationClass);//启动各个SpringApplicationRunListener 监听器实例(EventPublishingRunListener)
5.初始化默认应用参数类
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
6.根据运行监听器和应用参数来准备 Spring 环境,springboot2.0当中一共定义了三种环境:none, servlet, reactive
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
// Create and configure the environment
//根据应用类型,创建应用环境:如得到系统的参数、JVM及Servlet等参数
ConfigurableEnvironment environment = getOrCreateEnvironment();
//环境属性配置
//加载系统的属性配置来源
configureEnvironment(environment, applicationArguments.getSourceArgs());
//将sources封装成了一个名叫configurationProperties的ConfigurationPropertySourcesPropertySource对象,并把这个对象放到了sources的第一个位置。SpringConfigurationPropertySources是一个将MutablePropertySources转换成ConfigurationPropertySources的适配器
ConfigurationPropertySources.attach(environment);
//向监听器发送环境准备事件
listeners.environmentPrepared(bootstrapContext, environment);
//将DefaultProperties移动到列表最后
DefaultPropertiesPropertySource.moveToEnd(environment);
Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
"Environment prefix cannot be set via properties.");
//将environment中以spring.main开头的source绑定到springApplication中
bindToSpringApplication(environment);
//将环境转换为与application能够匹配的类型
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
//使配置的环境参数与环境匹配
ConfigurationPropertySources.attach(environment);
return environment;
}
7.设置需要忽略的bean,读取spring.beaninfo.ignore
8.打印启动的banner图,默认为Spring,如需自定义,可修改resources下的banner.txt文件
文字转txt
http://patorjk.com/software/taag/#p=display&h=0&v=1&f=3D%20Diagonal&t=Type%20Something%20
图片转txt
https://www.degraeve.com/img2txt.php
9.创建spring容器
10.准备容器主要是调用所有初始化类的initialize方法,准备上下文的资源
(1)将准备好的environment设置给applicationContext
(2)向beanFactory中添加了一个beanNameGenerator,BeanNameGenerator用来生成扫描到的Bean在容器中的名字
(3)遍历调用所有的ApplicationContextInitializer的initialize()来对已经创建好的ApplicationContext进行进一步的处理
(4)调用SpringApplicationRunListener的contextPrepared()方法,通知所有的监听者,ApplicationContext已经准备完毕
(5)调用SpringApplicationRunListener的contextLoaded()方法,通知所有的监听者,ApplicationContext已经装载完毕
11.完善上下文,加载业务bean,启动tomcat,发布对应事件
12.执行Spring容器的初始化的后置逻辑,默认为空
13.通知SpringApplicationRunListeners的,Spring容器启动完成
14.调用ApplicationRunner或CommandLineRunner的运行方法