springboot启动过程(基于版本2.0.5.release)
直接上代码
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
进到run
public static ConfigurableApplicationContext run(Class<?> primarySource,
String... args) {
return run(new Class<?>[] { primarySource }, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources,
String[] args) {
//第一步 new SpringApplication
//第二步 执行run
return new SpringApplication(primarySources).run(args);
}
第一步new SpringApplication
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 判断是否是web程序并且赋值
this.webApplicationType = deduceWebApplicationType();
// 从spring.factories文件中找出key为ApplicationContextInitializer的类并实例化后设置到SpringApplication的initializers属性中。这个过程也就是找出所有的应用程序初始化器
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
// 从spring.factories文件中找出key为ApplicationListener的类并实例化后设置到SpringApplication的listeners属性中。这个过程就是找出所有的应用程序事件监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//找到main方法
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
Banner printedBanner = printBanner(environment);
//创建spring容器
context = createApplicationContext();
//获取并打印Spring启动过程中的异常信息
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);
//找出Spring容器中Runner接口的实现类,然后执行(ApplicationRunner,CommandLineRunner)
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;
}
prepareContext
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
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
// 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);
}
总结
SpringBoot启动的时候,不论调用什么方法,都会构造一个SpringApplication的实例,然后调用这个实例的run方法,这样就表示启动SpringBoot。
在run方法调用之前,也就是构造SpringApplication的时候会进行初始化的工作,初始化的时候会做以下几件事:
- 把参数sources设置到SpringApplication属性中,这个sources可以是任何类型的参数。本文的例子中这个sources就是MyApplication的class对象
- 判断是否是web程序,并设置到webEnvironment这个boolean属性中
- 找出所有的初始化器,默认有5个,设置到initializers属性中
- 找出所有的应用程序监听器,默认有9个,设置到listeners属性中
- 找出运行的主类(main class)
SpringApplication构造完成之后调用run方法,启动SpringApplication,run方法执行的时候会做以下几件事:
- 构造一个StopWatch,观察SpringApplication的执行
- 找出所有的SpringApplicationRunListener并封装到SpringApplicationRunListeners中,用于监听run方法的执行。监听的过程中会封装成事件并广播出去让初始化过程中产生的应用程序监听器进行监听
- 构造Spring容器(ApplicationContext),并返回
3.1 创建Spring容器的判断是否是web环境,是的话构造AnnotationConfigEmbeddedWebApplicationContext,否则构造AnnotationConfigApplicationContext
3.2 初始化过程中产生的初始化器在这个时候开始工作
3.3 Spring容器的刷新(完成bean的解析、各种processor接口的执行、条件注解的解析等等) - 从Spring容器中找出ApplicationRunner和CommandLineRunner接口的实现类并排序后依次执行
刷新容器:https://www.jianshu.com/p/ab0b7df24c01
参考链接:https://fangjian0423.github.io/2017/04/30/springboot-startup-analysis/
网友评论