SpringBoot源码 - run方法启动流程
我们从主方法启动的入口开始,如下:
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
run方法主要干了两件事,一件是创建 SpringApplication 并进行初始化,初始化如下图:
文章图片
另一件是run的执行,我们重点看run的执行流程,一路点击run方法,直到:
文章图片
这个就是run方法启动的主流程了,下面一步步来看:
- 创建秒表计时器,开始计时
StopWatch stopWatch = new StopWatch(); stopWatch.start();
- 配置Headless属性
private void configureHeadlessProperty() {System.setProperty("java.awt.headless",System.getProperty("java.awt.headless",Boolean.toString(this.headless))); }
这里同一个属性,取了有设置回去,看起来一模一样,其实是因为 getProperty带两个参数的时候,会给默认值,所以再设置一次就能保证该属性都有值
- 从META-INF/spring.factories找到所有SpringApplicationRunListener的监听器,启动监听器
SpringApplicationRunListeners listeners = this.getRunListeners(args); listeners.starting(bootstrapContext, this.mainApplicationClass);
- 配置环境 ConfigurableEnvironment,加入到监听器对象中
ConfigurableEnvironment environment = this.prepareEnvironment(listeners,bootstrapContext, applicationArguments);
点击prepareEnvironment方法进去,方法里首先创建环境对象:
ConfigurableEnvironment environment = this.getOrCreateEnvironment();
接着配置环境:
this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
而 configureEnvironment()方法,会进行以下两个操作:
// 加载配置源参数和命令行属性 this.configurePropertySources(environment, args); // 配置当前activede的描述文件 this.configureProfiles(environment, args);
回到prepareEnvironment方法:
文章图片
准备系统环境:
listeners.environmentPrepared(bootstrapContext, (ConfigurableEnvironment)environment);
接下来bindToSpringApplication()方法:
protected void bindToSpringApplication(ConfigurableEnvironment environment) {
try {
Binder.get(environment).bind("spring.main", Bindable.ofInstance(this));
} catch (Exception var3) {
throw new IllegalStateException("Cannot bind to SpringApplication", var3);
}
}
将配置文件中的spring.main开头的配置信息绑定到SpringApplication类对应的属性中。
再回到run主流程中:
文章图片
- configureIgnoreBeanInfo
文章图片
设置忽略掉的bean
- 接下来是打印 banner:
Banner printedBanner = this.printBanner(environment);
- 【SpringBoot源码 - run方法启动流程】接着这一步比较重要,就是创建容器:
context = this.createApplicationContext();
- 接下来是prepareContext方法
文章图片
具体如下:
// 将环境变量设置到容器中
context.setEnvironment(environment);
// 对 ApplicationContext进行后置处理,设置beanNameGenerator、resourceLoader、classLoader和conversionService
this.postProcessApplicationContext(context);
// 获取之前获取到的所有 initializer 类型的类,并进行初始化
this.applyInitializers(context);
// 通知监听器context准备完成
listeners.contextPrepared(context);
// 打印profile信息
this.logStartupProfileInfo(context);
// 注册一个应用参数实例
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
// 注册 printedBanner实例
beanFactory.registerSingleton("springBootBanner", printedBanner);
// 设置是否允许同名bean,默认false
((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
// 获取,加载启动类,注入到容器中
Set
- refreshContext 刷新容器,完成组件的扫描、创建、加载等
this.refreshContext(context);
- 返回容器
return context;
总流程图如下:
文章图片
推荐阅读
- Activiti(一)SpringBoot2集成Activiti6
- SpringBoot调用公共模块的自定义注解失效的解决
- 解决SpringBoot引用别的模块无法注入的问题
- gitlab|gitlab 通过备份还原 admin/runner 500 Internal Server Error
- Android事件传递源码分析
- Quartz|Quartz 源码解析(四) —— QuartzScheduler和Listener事件监听
- [源码解析]|[源码解析] NVIDIA HugeCTR,GPU版本参数服务器---(3)
- ffmpeg源码分析01(结构体)
- Java程序员阅读源码的小技巧,原来大牛都是这样读的,赶紧看看!
- springboot使用redis缓存