Spring Boot 2.1.1.RELEASE Main方法启动详解二
程序员文章站
2022-05-29 18:34:13
...
二、SpringApplication.run(String... args)方法解析
public ConfigurableApplicationContext run(String... args) {
// 1.创建一个计时器,并启动计时器
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
// 2.配置java.awt.headless=true
configureHeadlessProperty();
// 3.创建发布事件的监听器,用于向ApplicationListener监听器发布不同消息
SpringApplicationRunListeners listeners = getRunListeners(args);
// 4.发布启动事件
listeners.starting();
try {
// 5.封装args参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 6.(*)加载环境参数
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
// 7.
configureIgnoreBeanInfo(environment);
// 8.创建banner,并打印banner
Banner printedBanner = printBanner(environment);
// 9.创建spring容器
context = createApplicationContext();
// 10.创建异常报告类
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context);
// 11.spring容器刷新前处理
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 12.刷新spring容器
refreshContext(context);
// 13.spring容器刷新后处理
afterRefresh(context, applicationArguments);
// 14.停止计时器
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
// 15.发布spring容器启动完成事件
listeners.started(context);
// 16.
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;
}
1.1 stopWatch.start()分析
public void start(String taskName) throws IllegalStateException {
if (this.currentTaskName != null) {
throw new IllegalStateException("Can't start StopWatch: it's already running");
}
this.currentTaskName = taskName;
// 记录当前时间毫秒值
this.startTimeMillis = System.currentTimeMillis();
}
分析:
记录当前时间的毫秒值,用于计算启动spring容器时耗时
1.2 配置headless系统变量参数
private void configureHeadlessProperty() {
System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
}
1.3 创建发布事件的监听器
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
// 1. 加载SpringApplicationRunListener对象
// 2. 创建SpringApplicationRunListeners对象,统一管理SpringApplicationRunListener对象
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
分析:
也是通过加载/META-INF/spring.factories中的配置类,创建EventPublishingRunListener时,将所有ApplicationListener交给其管理,并创建了SimpleApplicationEventMulticaster(*)类,它是真正发布事件的类
- EventPublishingRunListener
1.4 发布启动事件(SimpleApplicationEventMulticaster)
public void starting() {
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
1.5 封装args参数
public CommandLineArgs parse(String... args) {
CommandLineArgs commandLineArgs = new CommandLineArgs();
// 解析命令行中的参数
for (String arg : args) {
// 解析格式为:
// --spring.application.name=student
// --spring.application.name student
// --name
if (arg.startsWith("--")) {
String optionText = arg.substring(2, arg.length());
String optionName;
String optionValue = null;
if (optionText.contains("=")) {
optionName = optionText.substring(0, optionText.indexOf('='));
optionValue = optionText.substring(optionText.indexOf('=')+1, optionText.length());
} else {
optionName = optionText;
}
if (optionName.isEmpty() || (optionValue != null && optionValue.isEmpty())) {
throw new IllegalArgumentException("Invalid argument syntax: " + arg);
}
// 将解析出来的键值对存放到commandLineArgs中的map中
commandLineArgs.addOptionArg(optionName, optionValue);
}
// 解析格式为:
// aaa
else {
// 解析非--前缀的命令,添加到commandLineArgs中list中
commandLineArgs.addNonOptionArg(arg);
}
}
return commandLineArgs;
}
分析:解析命令行的参数,并封装到CommandLineArgs对象中
public PropertySource(String name, T source) {
Assert.hasText(name, "Property source name must contain at least one character");
Assert.notNull(source, "Property source must not be null");
// 默认传的名称为:commandLineArgs
this.name = name;
// 上一步解析出来的CommandLineArgs对象
this.source = source;
}
分析:封装解析出来的命令行参数CommandLineArgs到PropertySource(父类)->Source(子类)
public DefaultApplicationArguments(String[] args) {
Assert.notNull(args, "Args must not be null");
this.source = new Source(args);
this.args = args;
}
分析:再一次将Source和未解析的args封装到DefaultApplicationArguments中
1.6 加载环境变量
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// 获取配置环境,根据spring容器类型创建相应的StandardServletEnvironment
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 给environment.propertyResolver设置ConversionService
// 添加命令行参数到environment.propertySource
// 配置environment.activeProfiles
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 发布ApplicationEnvironmentPreparedEvent事件
listeners.environmentPrepared(environment);
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader())
.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}