- 1. 实例化SpringApplication
- 2. 运行run()方法
- 2.1. 获取SpringApplicationRunListener
- 2.2. 启动SpringApplicationRunListener.starting()方法
- 2.3. 准备环境
- 2.4. 配置忽略Bean信息
- 2.5. 打印Logo
- 2.6. 创建上下文容器
- 2.7. 获取SpringBootExceptionReporter
- 2.8. 准备上下文
- 2.9. 刷新容器refreshContext()
- 2.10. afterRefresh()
- 2.11.启动SpringApplicationRunListener.started()
- 2.12.ApplicationRunner和CommandLineRunner的run()方法
- 2.13.启动SpringApplicationRunListener.runing()方法
- 3.启动失败异常处理
先来一张图,对SpringBoot启动有个大概了解,再具体对每个方法进行分析.
通过上图可以看出Spring Boot 启动分为两部分,实例化SpringApplication类、运行run()方法。
public static void main(String[] args) {
SpringApplication.run(MySpringApplication.class, args);
}
1. 实例化SpringApplication
实例化SpringApplication 的内容很简单,只从META-INF/spring.factories中查找并实例化ApplicationContextInitializer、ApplicationListener类型的类,查找具有main()方法的类
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 = WebApplicationType.deduceFromClasspath();
// 从META-INF/spring.factories 文件中查找ApplicationContextInitializer类型的实现并实例化
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 从META-INF/Spring.factories 文件中查找ApplicationListeners 类型的实现并实例化
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 获取有main()方法的类
this.mainApplicationClass = deduceMainApplicationClass();
}
1.1.查找ApplicationContextInitializer
从META-INF/spring.factories文件中查找所有的org.springframework.context.ApplicationContextInitializer=定义的实现类名称,并实例化这些类。
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// 从META-INF/spring.factories文件中查找key=org.springframework.context.ApplicationContextInitializer的所有值
// 这些值是ApplicationContextInitializer接口实现的的全路径名称
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 实例化ApplicationContextInitializer接口实现类
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
1.2. 查找ApplicationListener
查找方式参照查找ApplicationContextInitializer
1.3. 查找main()方法的类
private Class<?> deduceMainApplicationClass() {
try {
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) {
// 查找具有main()方法的类,返回Class
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
}
catch (ClassNotFoundException ex) {
// Swallow and continue
}
return null;
}
1.4. 查找环境类型
SpringBoot的环境类型有三种,分别是NODE、SERVLET、REACTIVE。在启动时需要识别出具体是哪种类型的环境,后面在执行run()方法时,会根据环境实例化不同的容器。
static WebApplicationType deduceFromClasspath() {
// REACTIVE类型
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
// NODE类型
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
// SERVLET类型
return WebApplicationType.SERVLET;
}
2. 运行run()方法
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
// 获取所有SpringApplicationRunListeners类型的对象
// 从META-INF/spring.factories中获取所有定义好的SpringApplicationRunListeners 全路径名称
// 实例化这些实现类
SpringApplicationRunListeners listeners = getRunListeners(args);
// 执行SpringApplicationRunListener的starting()启动中方法
listeners.starting();
try {
// 封装命令行(main()方法参数)
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 准备环境
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
// 打印Logo
Banner printedBanner = printBanner(environment);
// 根据环境类型创建上下文容器,可以理解为实例化上下文对象
// 环境类型有SERVLET、REACTIVE、NODE
// SERVLET 类型创建org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext对象
// REACTIVE 类型创建org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext对象
// NODE 类型创建org.springframework.context.annotation.AnnotationConfigApplicationContext
context = createApplicationContext();
// 从spring.factories中获取异常处理器
// 当SpringBoot启动失败时,异常处理器会被执行
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// 准备上下文,对创建的上下文对象做相应的初始工作
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// Spring部分,启动SpringIOC容器
refreshContext(context);
// 容器启动完后置处理,空方法由子类实现
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
// 执行SpringApplicationRunListener 的started()启动完成方法
listeners.started(context);
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;
}
2.1. 获取SpringApplicationRunListener
从META-INF/spring.factories中获取SpringApplicationRunListener 定义的类并实例化,这个接口的的作用是在SpringBoot启动过程中,在不同阶段做一些业务处理。
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
// 首先从META-INF/spring.factories中获取所有SpringApplicationRunListener定义的全类名称
// 然后实例化这些类,返回一个List结合
// 封装到SpringApplicationRunListeners 对象中,在不同的阶段循环的调用对应方法
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
SpringApplicationRunListener接口定义6个方法,每个方法会在SpringBoot启动的不同阶段执行。
public interface SpringApplicationRunListener {
/**
* 在启动run()方法后立刻调用,可以用于做一些SpringBoot启动前的初始化工作
*/
default void starting() {
}
/**
* 在环境准备完成,ApplicationContext上下文容器没有创建之前调用
*/
default void environmentPrepared(ConfigurableEnvironment environment) {
}
/**
* ApplicationContext上下文准备完成,准备上下文前调用
*/
default void contextPrepared(ConfigurableApplicationContext context) {
}
/**
* 上下文ApplicationContext 准备完成时调用
*/
default void contextLoaded(ConfigurableApplicationContext context) {
}
/**
* 在容器刷新(启动)完成,CommandLineRunner和ApplicationRunner 没有被执行前调用
*/
default void started(ConfigurableApplicationContext context) {
}
/**
* 在CommandLineRunner和ApplicationRunner被执行后调用,到这里表示SpringBoot已经启动完成
*/
default void running(ConfigurableApplicationContext context) {
}
/**
* 在SpringBoot启动出现异常时被调用
*/
default void failed(ConfigurableApplicationContext context, Throwable exception) {
}
}
2.1.1. 默认实现EventPublishingRunListener
SprongBoot 为SpringApplicationRunListener接口提供了一个实现类EventPublishingRunListener。它的作用是发送事件,在不同的阶段发送不同的事件,这样监听器就能监听到SpringBoot的启动情况。
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
private final SpringApplication application;
private final String[] args;
private final SimpleApplicationEventMulticaster initialMulticaster;
/**
* 构造方法,实例化事件广播器,往事件广播器中添加监听器
*/
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
// 实例化事件广播器
this.initialMulticaster = new SimpleApplicationEventMulticaster();
// 将监听器添加到事件广播器中
// 这些监听器是在SpringApplication构造方法中,从META-INF/spring.factories中获取的
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
/**
* 在启动执行run()方法时发布ApplicationStartingEvent事件,用于监听SpringBoot启动前的事件
*/
@Override
public void starting() {
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
/**
* 环境准备完成后发布ApplicationEnvironmentPreparedEvent 事件
* @param environment
*/
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
this.initialMulticaster
.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
}
/**
* 在执行完ApplicationContextInitializer初始化方法后,准备上下文容器前发布ApplicationContextInitializedEvent事件
* @param context
*/
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
this.initialMulticaster
.multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
}
/**
* 上下文容器准备完成后发布ApplicationPreparedEvent 事件
* 将ApplicationListener类型的监听器加到上下文中的事件广播器中
* 注意这里和EventPublishingRunListener构造方法不同的是构造方法是把监听器加入到initialMulticaster事件广播器中
* 这里是把监听器加入到上下文中的事件广播器中,是不同的事件广播器。
* @param context
*/
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
// 将事件监听器加入到上下文中的事件广播器中
for (ApplicationListener<?> listener : this.application.getListeners()) {
if (listener instanceof ApplicationContextAware) {
((ApplicationContextAware) listener).setApplicationContext(context);
}
context.addApplicationListener(listener);
}
// 发布ApplicationPreparedEvent 事件
this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
}
/**
* 容器启动完成后,执行ApplicationRunner和CommandLineRunner的run()方法之前发布ApplicationStartedEvent和AvailabilityChangeEvent事件
* 这里的事件已经不是initialMulticaster事件广播器发布了,是上下文中的事件广播器来发布的
*/
@Override
public void started(ConfigurableApplicationContext context) {
context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
AvailabilityChangeEvent.publish(context, LivenessState.CORRECT);
}
/**
* 执行完ApplicationRunner和CommandLineRunner的run()方法之后,发布ApplicationReadyEvent和AvailabilityChangeEvent事件
* 事件通过上下文中的事件广播器发布
*/
@Override
public void running(ConfigurableApplicationContext context) {
context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));
AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);
}
/**
* SpringBoot启动失败时执行,发布ApplicationFailedEvent事件
*/
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
ApplicationFailedEvent event = new ApplicationFailedEvent(this.application, this.args, context, exception);
// 容器处于激活状态,直接发送事件
if (context != null && context.isActive()) {
// 用上下文中的事件广播器发布ApplicationFailedEvent事件
context.publishEvent(event);
}
else {
// 上下文不处于激活状态,采用initialMulticaster 事件广播器发布事件
// 上下文是AbstractApplicationContext类型
// 将监听器加入到initialMulticaster 事件广播器中
if (context instanceof AbstractApplicationContext) {
for (ApplicationListener<?> listener : ((AbstractApplicationContext) context)
.getApplicationListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
// 监听器抛出异常时的处理Handler
// 当监听器抛出异常时,通过这个Handler处理一些异常
this.initialMulticaster.setErrorHandler(new org.springframework.boot.context.event.EventPublishingRunListener.LoggingErrorHandler());
// 发布ApplicationFailedEvent 事件
this.initialMulticaster.multicastEvent(event);
}
}
/**
* 监听器抛出异常后处理的Handler
*/
private static class LoggingErrorHandler implements ErrorHandler {
private static final Log logger = LogFactory.getLog(org.springframework.boot.context.event.EventPublishingRunListener.class);
@Override
public void handleError(Throwable throwable) {
logger.warn("Error calling ApplicationEventListener", throwable);
}
}
}
2.2. 启动SpringApplicationRunListener.starting()方法
在执行run()方法后,立刻调用starting()方法做一些启动前的初始化工作。因为所有的SpringApplicationRunListener实现类对象都封装在SpringApplicationRunListeners对象中,执行时都是执行这个封装类,在封装类中循环的调用方法。典型的有EventPublishingRunListener实现类,向事件广播器发布ApplicationStartingEvent事件
void starting() {
// 循环调用starting()方法
for (SpringApplicationRunListener listener : this.listeners) {
listener.starting();
}
}
2.3. 准备环境
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// 根据环境类型获取环境对象
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 配置环境参数
configureEnvironment(environment, applicationArguments.getSourceArgs());
// ???
ConfigurationPropertySources.attach(environment);
// 环境准备完成,执行SpringApplicationRunListener.environmentPrepared()
listeners.environmentPrepared(environment);
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
2.3.1. 启动SpringApplicationRunListener.enviromentPrepared()
在环境准备完成后,创建上下文之前执行enviromentPrepared()方法
void environmentPrepared(ConfigurableEnvironment environment) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.environmentPrepared(environment);
}
}
2.4. 配置忽略Bean信息
如果没有通过jvm属性配置属性spring.beaninfo.ignore,那么设置属性spring.beaninfo.ignore的值为true
private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {
// 如果jvm启动属性配置没有spring.beaninfo.ignore,那么设置默认值为true
if (System.getProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) {
// 获取属性spring.beaninfo.ignore的值,默认为true
Boolean ignore = environment.getProperty("spring.beaninfo.ignore", Boolean.class, Boolean.TRUE);
//设置spring.beaninfo.ignore数值为true
System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME, ignore.toString());
}
}
2.5. 打印Logo
打印SpringBoot启动时的LOGO,可以自己DIY一个打印LOGO
private Banner printBanner(ConfigurableEnvironment environment) {
if (this.bannerMode == Banner.Mode.OFF) {
return null;
}
ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader
: new DefaultResourceLoader(getClassLoader());
SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);
if (this.bannerMode == Mode.LOG) {
return bannerPrinter.print(environment, this.mainApplicationClass, logger);
}
return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}
2.6. 创建上下文容器
创建上下文容器,可以理解为实例化一个容器对象。根据环境类型来决定实例化哪个容器对象。容器对象都是ConfigurableApplicationContext类的子类。
环境类型有三种,意味着有三种容器容器对象,分别为:
SERVLET类型:实例化org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext REACTIVE 类型创建org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext NODE 类型创建org.springframework.context.annotation.AnnotationConfigApplicationContext
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
// 没有指定容器
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
// SERVLET类型的容器
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
// REACTIVE 类型的容器
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
// NONE 类型的容器
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);
}
2.7. 获取SpringBootExceptionReporter
SpringBootExceptionReporter 接口的作用是在SpringBoot启动失败时被执行,通过实现该接口,在启动出现异常时,能够做一些启动失败的业务处理。默认实现有FailureAnalyzers类。
// 从spring.factories文件中获取SpringBootExceptionReporter接口的子类全类名称
// 并实例化这些子类
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
2.8. 准备上下文
在2.6节中,根据环境创建了上下文对象,在这里我们会对上下文对象进行一些准备工作
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
// 为上下文设置环境对象
context.setEnvironment(environment);
postProcessApplicationContext(context);
// 执行ApplicationContextInitializer接口的初始化方法
applyInitializers(context);
// 执行容器准备完成方法
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// 获取BeanFactory工程对象
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 向容器中添加单实例bean applicationArguments对象
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
// 向容器中添加单实例bean printedBanner对象
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
// 如果是DefaultListableBeanFactory bean工厂对象
if (beanFactory instanceof DefaultListableBeanFactory) {
// 当出现bean的名称相同时,允许覆盖bean定义信息的标识
// true 允许覆盖,false不允许覆盖
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
// 添加BeanFactoryPostProcessor 后置处理器LazyInitializationBeanFactoryPostProcessor
// 这个后置处理器的作用是决定是否需要对一些bean进行延迟加载
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
// 执行容器加载完成方法
listeners.contextLoaded(context);
}
2.8.1.执行ApplicationContextInitializer初始化方法
在容器准备前,先执行ApplicationContextInitializer接口的initialize()方法,该接口的子类在实例化SpringApplication时已经被实例化,具体怎么实例化的看1.1
protected void applyInitializers(ConfigurableApplicationContext context) {
// 循环执行AplicationContextInitializer接口的初始化方法initialize()方法
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
initializer.initialize(context);
}
}
2.8.2. 启动SpringApplicationRunListener.contextPrepared()
在执行完初始化方法后,执行SpringApplicationRunListener接口的contextPrepared()方法。
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
this.initialMulticaster
.multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
}
2.8.3. 加载BeanDefinition
加载所有需要被创建的Bean信息,组装成BeanDefinition对象,这里不做分析。可以看Bean的配置文件加载源码分析
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
if (this.beanNameGenerator != null) {
loader.setBeanNameGenerator(this.beanNameGenerator);
}
if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}
if (this.environment != null) {
loader.setEnvironment(this.environment);
}
loader.load();
}
2.8.4. 启动SpringApplicationRunListener.contextLoaded()
在容器加载完成后,执行SpringApplicationRunListener接口的contextLoaded()方法。典型的实现类有EventPublishingRunListener
void contextLoaded(ConfigurableApplicationContext context) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.contextLoaded(context);
}
}
2.9. 刷新容器refreshContext()
刷新容器这部分内容是Spring 部分,这里不做详述
2.10. afterRefresh()
这是一个空方法,留给子类实现。在容器刷新完成后执行
2.11.启动SpringApplicationRunListener.started()
在容器刷新完成后,意味着SpringBoot已经启动完成,接下来会执行SpringApplicationRunListener接口的started()方法。
void started(ConfigurableApplicationContext context) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.started(context);
}
}
2.12.ApplicationRunner和CommandLineRunner的run()方法
执行ApplicationRunner和CommandLineRunner接口的run()方法,一般应用于在容器启动后,启动一些后台任务来做一些业务处理
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<>();
// 查找所有ApplicationRunner类型的Bean
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
// 查找所有CommandLineRunner类型的Bean
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
// 排序
AnnotationAwareOrderComparator.sort(runners);
for (Object runner : new LinkedHashSet<>(runners)) {
// 执行ApplicationRunner接口的run()方法
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
// 执行CommandLineRunner类型的run()方法
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}
2.13.启动SpringApplicationRunListener.runing()方法
程序执行到这里,表示SpringBoot已经启动完成了,已经是一个正常启动的应用了。此时执行SpringApplicationRunListener接口的runing()方法。
void running(ConfigurableApplicationContext context) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.running(context);
}
}
3.启动失败异常处理
在SpringBoot启动失败时,会通过SpringBootExceptionReporter接口来处理启动的异常业务。我们可以实现该接口,在启动失败时来处理启动失败的异常。比如:发布启动失败事件等。
private void handleRunFailure(ConfigurableApplicationContext context, Throwable exception,
Collection<SpringBootExceptionReporter> exceptionReporters, SpringApplicationRunListeners listeners) {
try {
try {
handleExitCode(context, exception);
// 执行SpringApplicationRunListener接口的failed()方法
// 默认实现类EventPublishingRunListener
if (listeners != null) {
listeners.failed(context, exception);
}
}
finally {
reportFailure(exceptionReporters, exception);
if (context != null) {
context.close();
}
}
}
catch (Exception ex) {
logger.warn("Unable to close ApplicationContext", ex);
}
ReflectionUtils.rethrowRuntimeException(exception);
}
3.1 EventPublishingRunListener默认实现
在SpringBoot启动失败时,会执行SpringApplicationRunListener接口的failed()方法,这个接口的默认实现类EventPublishingRunListener中的failed()方法会发布ApplicationFailedEvent事件
EventPublishingRunListener的failed()方法
public void failed(ConfigurableApplicationContext context, Throwable exception) {
ApplicationFailedEvent event = new ApplicationFailedEvent(this.application, this.args, context, exception);
// 如果上下文容器此时已经激活,发布ApplicationFailedEvent事件
if (context != null && context.isActive()) {
// Listeners have been registered to the application context so we should
// use it at this point if we can
context.publishEvent(event);
}
else {
// 容器没有激活,说明还没有向容器中添加监听器,此时需要向容器中添加监听器
if (context instanceof AbstractApplicationContext) {
// 向容器中添加监听器
for (ApplicationListener<?> listener : ((AbstractApplicationContext) context)
.getApplicationListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
// 事件发布失败时处理的Handler
this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
// 发布ApplicationFailedEvent事件
this.initialMulticaster.multicastEvent(event);
}
}