1前言
这篇主要讲讲springboot应用(使用的版本是:2.0.1.RELEASE)启动过程.
2启动过程分析
启动springboot应用最简单方式,只有一行代码如下所示
@SpringBootApplication
public class QuickStartApplication {
public static void main(String[]args){
SpringApplication.run(QuickStartApplication.class,args);
}
}
在SpringApplication
类的注释里说明它的作用,在java的main方法里构建,启动一个spring 应用.默认情况下执行以下几个步骤来构建我们的应用:
- 根据classpath创建一个ApplicationContext实例
- 注册一个CommandLinePropertySource将命令行参数保存起来作为spring properties
- refresh ApplicationContext ,加载所有的单例bean
- 触发ApplicationRunner or CommandLineRunnerbean的run方法调用.官方文档传送门CommandLineRunner使用
接下来看看源码里头怎么实现以上四个步骤的.
2.1初始化SpringApplication
SpringApplication
调用静态方法run(),这个静态方法先实例化一个SpringApplication
,然后再执行具体的run()方法.代码截图如下:
在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));
//推测应用类型
this.webApplicationType = deduceWebApplicationType();
//通过SpringFactoriesLoader从/META-INF/spring.factories获取ApplicationContextInitializer信息,
并实例化ApplicationContextInitializer
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
//通过SpringFactoriesLoader从/META-INF/spring.factories获取ApplicationListener信息,并实例化ApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//判断传入primarySources类是否包含main方法
this.mainApplicationClass = deduceMainApplicationClass();
}
2.2非静态run方法调用
在2.1中介绍了SpringApplication的初始化过程.接下来就看看run方法都干了啥.
public ConfigurableApplicationContext run(String... args) {
//定义StopWatch,用于监控应用启动耗时,分析性能
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
//获取一个SpringApplicationRunListeners 实例,监控spring应用启动的执行过程,并发布相应事件(starting,environmentPrepared,contextPrepared,contextLoaded,started,running,failed)
SpringApplicationRunListeners listeners = getRunListeners(args);
//正在启动
listeners.starting();
try {
//保存传递过来的命令行参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
//根据webApplicationType类型得到ConfigurableEnvironment
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
//打印banner,就启动的时候那个超级大的'spring'.如果想自定义,只需要把对应banner.txt
(需要打印的内容,网上有不少在线生成banner样式的网站)放置resource目录即可
Banner printedBanner = printBanner(environment);
//根据webApplicationType创建applicationcontext
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//context预处理,设置Environment
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//最核心的一步:加载,生成各种自动化配置bean,它调用栈如图2所示,最终调用到@EnableAutoConfiguration里@import AutoConfigurationImportSelector
refreshContext(context);
afterRefresh(context, applicationArguments);
//停止监控
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
//发布启动事件
listeners.started(context);
//调用runner
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
//发布context正在运行事件
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
stack.png
3小结
从上面的源码可以看出,springboot启动的时候,主要干了一件事:完成ApplicationContext的创建以及bean创建.
网友评论