- 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()方法的类,返回Classif ("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);// 打印LogoBanner 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.AnnotationConfigApplicationContextcontext = 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启动前的事件*/@Overridepublic void starting() {this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));}/*** 环境准备完成后发布ApplicationEnvironmentPreparedEvent 事件* @param environment*/@Overridepublic void environmentPrepared(ConfigurableEnvironment environment) {this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));}/*** 在执行完ApplicationContextInitializer初始化方法后,准备上下文容器前发布ApplicationContextInitializedEvent事件* @param context*/@Overridepublic void contextPrepared(ConfigurableApplicationContext context) {this.initialMulticaster.multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));}/*** 上下文容器准备完成后发布ApplicationPreparedEvent 事件* 将ApplicationListener类型的监听器加到上下文中的事件广播器中* 注意这里和EventPublishingRunListener构造方法不同的是构造方法是把监听器加入到initialMulticaster事件广播器中* 这里是把监听器加入到上下文中的事件广播器中,是不同的事件广播器。* @param context*/@Overridepublic 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事件广播器发布了,是上下文中的事件广播器来发布的*/@Overridepublic void started(ConfigurableApplicationContext context) {context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));AvailabilityChangeEvent.publish(context, LivenessState.CORRECT);}/*** 执行完ApplicationRunner和CommandLineRunner的run()方法之后,发布ApplicationReadyEvent和AvailabilityChangeEvent事件* 事件通过上下文中的事件广播器发布*/@Overridepublic void running(ConfigurableApplicationContext context) {context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);}/*** SpringBoot启动失败时执行,发布ApplicationFailedEvent事件*/@Overridepublic 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);@Overridepublic 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,那么设置默认值为trueif (System.getProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) {// 获取属性spring.beaninfo.ignore的值,默认为trueBoolean ignore = environment.getProperty("spring.beaninfo.ignore", Boolean.class, Boolean.TRUE);//设置spring.beaninfo.ignore数值为trueSystem.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 sourcesSet<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()方法。
@Overridepublic 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类型的Beanrunners.addAll(context.getBeansOfType(ApplicationRunner.class).values());// 查找所有CommandLineRunner类型的Beanrunners.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()方法// 默认实现类EventPublishingRunListenerif (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 cancontext.publishEvent(event);}else {// 容器没有激活,说明还没有向容器中添加监听器,此时需要向容器中添加监听器if (context instanceof AbstractApplicationContext) {// 向容器中添加监听器for (ApplicationListener<?> listener : ((AbstractApplicationContext) context).getApplicationListeners()) {this.initialMulticaster.addApplicationListener(listener);}}// 事件发布失败时处理的Handlerthis.initialMulticaster.setErrorHandler(new LoggingErrorHandler());// 发布ApplicationFailedEvent事件this.initialMulticaster.multicastEvent(event);}}
