目录
前言
上一篇:SpringBoot源码分析之-启动流程分析一(SpringApplication构造器)分析了SpringApplication的构造初始化,初始化主要设置加载类,项目类型(非web,servlet web,响应式web),上下文初始化器,监听器,程序主入口. 还介绍了一些方法的实现.
这篇主要分析run方法做了什么事情
run主要流程介绍
1.创建一个StopWatch,用于监控启动过程
2.设置程序为无显示模式
3.获取监听器SpringApplicationRunListener,用于启动过程的事件广播
4.广播启动事件(ApplicationStartingEvent)
5.环境准备 environment 广播
6.创建上下文
7.获取SpringBootExceptionReporter , (启动失败的异常信息日志)
8.准备上下文
9.刷新上下文
10.刷新上下文之后的一些扩展 (现在是空的,有需要自己可以重写)
11.输出启动的时间
12.广播启动成功事件
13. callRunners 执行自定义的业务代码(比如业务初始化)
13.广播运行成事件
/**
* Run the Spring application, creating and refreshing a new
* {@link ApplicationContext}.
* @param args the application arguments (usually passed from a Java main method)
* @return a running {@link ApplicationContext}
*/
public ConfigurableApplicationContext run(String... args) {
//创建一个StopWatch,用于监控启动过程
StopWatch stopWatch = new StopWatch();
//启动时间戳:纳秒
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
//设置了系统全局变量 java.awt.headless, true
//用于在缺失显示屏、鼠标或者键盘时的系统配置,也就是Web服务
configureHeadlessProperty();
//获取监听器SpringApplicationRunListener,用于启动时的事件广播
SpringApplicationRunListeners listeners = getRunListeners(args);
//广播ApplicationStartingEvent事件
listeners.starting();
try {
// 参数封装
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 准备环境:命令行参数,系统参数,配置文件,外部配置文件,(非web/web/响应式web)项目环境
//2、广播ApplicationEnvironmentPreparedEvent事件
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
// 设置系统变量spring.beaninfo.ignore, true
configureIgnoreBeanInfo(environment);
//打印banner
Banner printedBanner = printBanner(environment);
// 创建ConfigurableApplicationContext 应用上下文容器
context = createApplicationContext();
//创建SpringBootExceptionReporter, 启动异常后的相关处理
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//准备容器
//广播ApplicationEnvironmentPreparedEvent事件
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);
//可以执行一些业务初始化 通过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;
}
方法介绍
configureHeadlessProperty();
设置请求头
private void configureHeadlessProperty() {
// private static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = "java.awt.headless";
System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
}
getRunListeners()
//获取EventPublishingRunListener实例
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {
this.log = log;
this.listeners = new ArrayList<>(listeners);
}
通过类路径下所有的 META-INF/spring.factories获取SpringApplicationRunListener的实现类,目前只有一个EventPublishingRunListener
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
SpringApplicationRunListener相关代码分析放在下一篇介绍
createApplicationContext()
根据构建SpringApplication是确定的项目类型, 创建不同上下文
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
refreshContext(context);
刷新上下文, 就是初始化Spring项目. 具体行为后续博客再分析
afterRefresh(context, applicationArguments);
刷新上下文之后的一些扩展,现在是空方法
callRunners(context, applicationArguments);
业务相关初始化代码可以通过实现ApplicationRunner 或 CommandLineRunner来实现.
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<>();
//容器里获取ApplicationRunner实现bean
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
//获取CommandLineRunner
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
//排序
AnnotationAwareOrderComparator.sort(runners);
for (Object runner : new LinkedHashSet<>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}
private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
try {
(runner).run(args);
}
catch (Exception ex) {
throw new IllegalStateException("Failed to execute ApplicationRunner", ex);
}
}
private void callRunner(CommandLineRunner runner, ApplicationArguments args) {
try {
(runner).run(args.getSourceArgs());
}
catch (Exception ex) {
throw new IllegalStateException("Failed to execute CommandLineRunner", ex);
}
}