运行阶段是Spring Boot的核心过程,主要围绕public ConfigurableApplicationContext run(String... args) 方法展开,该过程结合初始化阶段完成的状态,进一步完善了运行时所需要的资源,随后启动ApplicationContext上下文,整个流程可分为上下文启动前阶段,上下文装备阶段,上下文启动阶段和上下文启动后阶段。在此期间,触发spring和spring boot的事件,形成完整的SpringApplication的生命周期。run方法源码如下 :
public ConfigurableApplicationContext run(String... args) {
//秒表
StopWatch stopWatch = new StopWatch();
//开始计时
stopWatch.start();
//声明Spring上下文
ConfigurableApplicationContext context = null;
//异常报告
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
//根据“java.awt.headless”配置Headless,用于在缺少显示屏、键盘或者鼠标时的系统配置,很多监控工具如jconsole 需要将该值设置为true,可以忽略
configureHeadlessProperty();
//获取listeners
SpringApplicationRunListeners listeners = getRunListeners(args);
//开始监听,EventPublishingRunListener发布ApplicationStartingEvent事件
listeners.starting();
try {
//对args参数的封装,args可以是在命令行中的参数,也可以是在main方法设置的参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//初始化可配置的Environment,EventPublishingRunListener发布ApplicationEnvironmentPreparedEvent事件
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
//得到系统属性spring.beaninfo.ignore,如果为空设置为true
configureIgnoreBeanInfo(environment);
//如果未设置banner的mode为off,则输出banner
Banner printedBanner = printBanner(environment);
//根据构造函数中的webApplicationType来初始化spring上下文,有WebApplicationContext,ConfigurableWebServerApplicationContext,ConfigurableReactiveWebApplicationContext三种
context = createApplicationContext();
//错误分析报告
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) {
//打印启动日志,我们经常看到的。。。with PID 17848。。。。就是这里打印的
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
//默认EventPublishingRunListener发布ApplicationStartedEvent事件
listeners.started(context);
//从容器中获取ApplicationRunner和CommandLineRunner,并调用其run方法
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
//异常处理
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
//默认EventPublishingRunListener发布ApplicationReadyEvent事件
listeners.running(context);
}
catch (Throwable ex) {
//异常处理
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
上下文启动前阶段
StopWatch
秒表,用来计时,类似实现有apache commons和guava,调用了start方法,在下一次调用start方法或前必须保证其stop方法被调用,否则抛出IllegalStateException异常
SpringBootExceptionReporter
使用SpringFactoriesLoader.loadFactoryNames加载META-INF/spring.factories中的SpringBootExceptionReporter,默认实现仅FailureAnalyzers,ConfigurableApplicationContext为其构造函数参数。FailureAnalyzers组合模式List<FailureAnalyzer> analyzers,而FailureAnalyzer的实现依然通过SpringFactoriesLoader.loadFactoryNames实现,默认实现如下:
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanDefinitionOverrideFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindValidationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.UnboundConfigurationPropertyFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoSuchMethodFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer
当我们在实现自己的starter的时候,可以自定义FailureAnalyzer实现,从而引导使用人员正确使用其starter
SpringApplicationRunListeners
同样使用组合模式,将构造函数中加载的listeners放入其类型为List<SpringApplicationRunListener> 的listeners字段中,默认实现仅EventPublishingRunListener。EventPublishingRunListener不仅能监听spring boot定义的事件,同样也监听spring的事件,当其contextLoaded(ConfigurableApplicationContext context)方法被调用时,将其listeners增加到了spring的ConfigurableApplicationContext的applicationListeners属性中。
contextLoaded(ConfigurableApplicationContext context)方法源码如下:
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
for (ApplicationListener<?> listener : this.application.getListeners()) {
if (listener instanceof ApplicationContextAware) {
((ApplicationContextAware) listener).setApplicationContext(context);
}
context.addApplicationListener(listener);
}
this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
}
而contextLoader方法是其run方法中的准备上下文prepareContext方法中调用的
上下文准备阶段
该阶段由prepareContext方法完成,在该方法中,EventPublishingRunListener发布ApplicationContextInitializedEvent事件和ApplicationPreparedEvent事件
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment
environment, SpringApplicationRunListeners listeners, ApplicationArguments
applicationArguments, Banner printedBanner) {
//设置environment,有三种实现,spring的StandardEnvironment和StandardServletEnvironment,Spring boot的StandardReactiveWebEnvironment,三者并无多大区别
context.setEnvironment(environment);
//spring应用上下文后置处理,子类可以覆盖该实现
postProcessApplicationContext(context);
//应用spring上下文初始化器,迭代执行ApplicationContextInitializer的集合
applyInitializers(context);
//EventPublishingRunListener发布ApplicationContextInitializedEvent事件
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
//主要打印profiles相关日志
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//注册单例applicationArguments,可通过Autowire自动注入
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
//注册单例printedBanner
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
//当注册多个相同name的bean时,是否可覆盖,默认false,可通过SpringApplication的实例设置false
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
//合并Spring上下文配置源并去重
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
//加载spring上下文配置源,将spring上下文Bean的装载任务交给了BeanDefinitionLoader
load(context, sources.toArray(new Object[0]));
//EventPublishingRunListener发布ApplicationPreparedEvent事件
listeners.contextLoaded(context);
}
上下文启动阶段
该阶段由refreshContext(ConfigurableApplicationContext context)方法执行完成,源码如下
private void refreshContext(ConfigurableApplicationContext context) { //启动容器 refresh(context); if (this.registerShutdownHook) { try { //注册shutdownHoot线程,实现Spring bean销毁生命周期的回调 context.registerShutdownHook(); } catch (AccessControlException ex) { // Not allowed in some environments. } } }
首选调用refresh(ApplicationContext applicationContext)方法,在refresh方法内部,调用AbstractApplicationContext的refresh()方法执行ApplicationContext的启动。
上下文启动后阶段
afterRefresh(context, applicationArguments)方法是一个protected修饰的空方法,提供给子类扩展。
listeners.started(context)方法,默认逻辑只有EventPublishingRunListener发布ApplicationStartedEvent事件。
callRunners(context, applicationArguments)