SpringBoot源码-启动
SpringBoot源码-启动
源码解析
SpringBoot 的启动很简单,一行代码就能完成:
@SpringBootApplication
public class MySpringApplication {
public static void main(String[] args) {
ApplicationContext applicationContext = SpringApplication.run(MySpringApplication.class, args);
}
}
但在这简单的代码背后,SpringBoot帮助我们完成了事件的注册,容器的生成。今天追踪源码,看一下SpringBoot的启动背后,究竟做了哪些事情。
SpringApplication.run()的执行会首先新建一个SpringApplication的实例,然后调用实例的run函数。
public static ConfigurableApplicationContext run(Object source, String... args) {
return run(new Object[] { source }, args);
}public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
return new SpringApplication(sources).run(args);
}
新建SpringApplication实例,会调用initialize方法。
public SpringApplication(Object... sources) {
initialize(sources);
}private void initialize(Object[] sources) {
// 将source加载近实例的sources属性中
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
// bool类型,用来标识当前的环境是否为web环境
this.webEnvironment = deduceWebEnvironment();
// 将spring.factories中的ApplicationContextInitializer加载入实例的属性中
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
// 将spring.factories中的ApplicationListener加载入实例的属性中
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// trace 递归找出main函数所在的类
this.mainApplicationClass = deduceMainApplicationClass();
}
其中:
-
deduceWebEnvironment
函数用来判断当前的Application是否为web环境,判断的方法是去尝试实例化Servlet
,ConfigurableWebApplicationContext
,如果成功,则认为是,反之则为否。 -
setInitializers
和setListeners
是通过扫描spring.factories文件来完成的。该文件的位置为jar包的resource/META-INF文件夹下,需要注意的是,文件可以存在于多个jar包中,这不影响springboot启动时的扫描,所以如果需要自定义启动类和监听类,只需要在自己的jar包中添加文件即可。
public ConfigurableApplicationContext run(String... args) {
// 构建了一个任务执行的观察器,通过start和stop可以完成任务的计时
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
configureHeadlessProperty();
// 获取SpringApplicationRunListeners,内部只有一个EventPublishingRunListener
SpringApplicationRunListeners listeners = getRunListeners(args);
// 通过EventPublishingRunListener向所有注册的listener类发送ApplicationStartedEvent事件
listeners.started();
try {
// 构造一个应用程序参数持有类
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 创建spring容器
context = createAndRefreshContext(listeners, applicationArguments);
// spring容器创建完成后的回调任务
afterRefresh(context, applicationArguments);
// 通过EventPublishingRunListener向所有注册的listener类发送getFinishedEvent事件
listeners.finished(context, null);
// stop记录point
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
// 返回ConfigurableApplicationContext
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, ex);
throw new IllegalStateException(ex);
}
}
首先来说明一下
SpringApplicationRunListeners
,这个类在SpringBoot中只有一个实现:EventPublishingRunListener
。该类的ApplicationEventMulticaster
成员,其实充当了一个送报员的角色,在收到了报纸(主线程的通知)后,将根据订阅的人员名单(在Application中注册的Listener列表),进行事件的分发通知。执行的步骤如图:
文章图片
@SpringApplicationRunListener执行步骤|center 具体的代码简略如下:
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {private final ApplicationEventMulticaster multicaster;
……@Override
public void finished(ConfigurableApplicationContext context, Throwable exception) {
publishEvent(getFinishedEvent(context, exception));
}……// 事件的分发
private void publishEvent(SpringApplicationEvent event) {
this.multicaster.multicastEvent(event);
}}
这样就很容易理解run函数中的
listener.start()
和listener.stop()
的作用了,用来标记启动的状态并通知各个注册的listener作出相应的操作。createAndRefreshContext
是创建Spring容器的过程:private ConfigurableApplicationContext createAndRefreshContext(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// 定义spring容器 context
ConfigurableApplicationContext context;
// 根据之前的webEnvironment来初始化相应的环境
//(StandardEnvironment或者StandardServletEnvironment)
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 配置环境信息
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 通过EventPublishingRunListener向所有注册的listener类
// 发送ApplicationEnvironmentPreparedEvent事件
listeners.environmentPrepared(environment);
// 重新校验环境信息
if (isWebEnvironment(environment) && !this.webEnvironment) {
environment = convertToStandardEnvironment(environment);
}// print 环境信息
if (this.bannerMode != Banner.Mode.OFF) {
printBanner(environment);
}// Create, load, refresh and run the ApplicationContext
// 创建Spring容器
context = createApplicationContext();
// 配置Spring容器
context.setEnvironment(environment);
// Spring容器创建之后需要做的回调方法
postProcessApplicationContext(context);
// 执行 SpringApplication 的初始化器
applyInitializers(context);
// 遍历调用SpringApplicationRunListener的contextPrepared方法
// 查看代码来看,只是将ApplicationEventMulticaster注册到Spring容器中
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}// Add boot specific singleton beans
// 把应用程序参数持有类注册到Spring容器中,并且是一个单例
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
// Load the sources
Set