上一篇分析了SpringApplication对象的构建过程及SpringBoot自己实现的一套SPI机制 ,关键步骤总结:
SpringApplication
对象的构造过程其实就是给SpringApplication
类的6 个成员变量赋值;
SpringBoot通过以下步骤实现自己的SPI机制:
1)首先获取线程上下文类加载器;
2)然后利用上下文类加载器从spring.factories
配置文件中加载所有的SPI扩展实现类并放入缓存中 ;
3)根据SPI接口从缓存中取出相应的SPI扩展实现类;
4)实例化从缓存中取出的SPI扩展实现类并返回。
1.SpringBoot广播内置生命周期事件流程分析 在SpringBoot启动过程中,每个不同的启动阶段会分别广播不同的内置生命周期事件,然后相应的监听器会监听这些事件来执行一些初始化逻辑工作。比如ConfigFileApplicationListener
会监听onApplicationEnvironmentPreparedEvent
事件来加载配置文件application.properties
的环境变量等。
为了探究SpringBoot广播内置生命周期事件流程,回顾一下SpringBoot的启动流程代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 public ConfigurableApplicationContext run(String ... args) { StopWatch stopWatch = new StopWatch (); stopWatch.start(); ConfigurableApplicationContext context = null ; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList <>(); configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments ( args); ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment); context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances( SpringBootExceptionReporter.class, new Class [] { ConfigurableApplicationContext.class }, context ); // 【3】》》》》》触发【ApplicationContextInitializedEvent 】事件,标志context 容器被创建且已准备好 // 【4】》》》》》触发【ApplicationPreparedEvent 】事件,标志Context 容器已经准备完成 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); 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; }
可以看到SpringBoot在启动过程中首先会先新建一个SpringApplicationRunListeners
对象用于触发SpringBoot启动过程中的各种生命周期事件,比如触发ApplicationStartingEvent
,ApplicationEnvironmentPreparedEvent
和ApplicationContextInitializedEvent
等事件,然后相应的监听器会执行一些SpringBoot启动过程中的初始化逻辑。那么,监听这些SpringBoot的生命周期事件的监听器们是何时被加载实例化的呢?根据之前的分析SpringApplication
的构建过程吗?这些执行初始化逻辑的监听器们正是在SpringApplication
的构建过程中根据ApplicationListener
接口去spring.factories
配置文件中加载并实例化的。
1.1 为广播SpringBoot内置生命周期事件做前期准备 1.1.1 加载ApplicationListener监听器实现类 前面分析到,在构建SpringApplication
对象时的setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
这句代码做的事情就是从spring.factories
中加载出ApplicationListener
事件监听接口的SPI扩展实现类然后添加到SpringApplication
对象的listeners
集合中,用于后续监听SpringBoot启动过程中的事件,来执行一些初始化逻辑工作。
SpringBoot启动时的具体监听器们都实现了ApplicationListener
接口,其在spring.factories
部分配置如下:
spring-boot-2.1.0.RELEASE\spring-boot-project\spring-boot\src\main\resources\META-INF\spring.factories
1 2 3 4 5 6 7 8 9 10 11 org.springframework.context.ApplicationListener=\ org.springframework.boot.ClearCachesApplicationListener,\ org.springframework.boot.builder.ParentContextCloserApplicationListener,\ org.springframework.boot.context.FileEncodingApplicationListener,\ org.springframework.boot.context.config.AnsiOutputApplicationListener,\ org.springframework.boot.context.config.ConfigFileApplicationListener,\ org.springframework.boot.context.config.DelegatingApplicationListener,\ org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\ org.springframework.boot.context.logging.LoggingApplicationListener,\ org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
1.1.2 加载SPI扩展类EventPublishingRunListener 前面讲到,在SpringBoot的启动过程中首先会先新建一个SpringApplicationRunListeners
对象用于触发SpringBoot启动过程中的生命周期事件,来看下SpringApplicationRunListeners listeners = getRunListeners(args);
这句代码:
1 2 3 4 5 6 7 8 private SpringApplicationRunListeners getRunListeners (String[] args ) { Class<?>[] types = new Class<?>[] { SpringApplication.class , String[].class }; return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class , types, this , args)); }
将重点放到getSpringFactoriesInstances( SpringApplicationRunListener.class, types, this, args)
这句代码,getSpringFactoriesInstances
这个方法在之前分析SpringBoot的SPI机制时已经详细分析过。可以看到SpringBoot此时又是根据SpringApplicationRunListener
这个SPI接口去spring.factories
中加载相应的SPI扩展实现类,直接去spring.factories
中看看SpringApplicationRunListener
有哪些SPI实现类:
1 2 3 org.springframework.boot.SpringApplicationRunListener =\ org.springframework.boot.context.event.EventPublishingRunListener
可以看到,SpringApplicationRunListener
只有EventPublishingRunListener
这个SPI实现类。
EventPublishingRunListener
在SpringBoot启动过程的不同阶段触发不同的SpringBoot的生命周期事件,即SpringApplicationRunListeners
对象没有承担广播事件的职责,而最终是委托EventPublishingRunListener
来广播事件的。
因为从spring.factories
中加载EventPublishingRunListener
类后还会实例化该类,那么再跟进EventPublishingRunListener
的源码,看看其是如何承担触发SpringBoot生命周期事件这一职责的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 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(); for (ApplicationListener<?> listener : application.getListeners()) { this .initialMulticaster.addApplicationListener(listener); } } @Override public int getOrder ( ) { return 0 ; } @Override public void starting ( ) { this .initialMulticaster.multicastEvent(new ApplicationStartingEvent(this .application, this .args)); } @Override public void environmentPrepared (ConfigurableEnvironment environment ) { this .initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(this .application, this .args, environment)); } @Override public void contextPrepared (ConfigurableApplicationContext context ) { this .initialMulticaster.multicastEvent(new ApplicationContextInitializedEvent(this .application, this .args, 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)); } @Override public void started (ConfigurableApplicationContext context ) { context.publishEvent(new ApplicationStartedEvent(this .application, this .args, context)); } @Override public void running (ConfigurableApplicationContext context ) { context.publishEvent(new ApplicationReadyEvent(this .application, this .args, context)); } @Override public void failed (ConfigurableApplicationContext context, Throwable exception ) { ApplicationFailedEvent event = new ApplicationFailedEvent(this .application, this .args, context, exception); if (context != null && context.isActive()) { context.publishEvent(event); } else { if (context instanceof AbstractApplicationContext) { for (ApplicationListener<?> listener : ((AbstractApplicationContext) context).getApplicationListeners()) { this .initialMulticaster.addApplicationListener(listener); } } this .initialMulticaster.setErrorHandler(new LoggingErrorHandler()); this .initialMulticaster.multicastEvent(event); } } private static class LoggingErrorHandler implements ErrorHandler { private static Log logger = LogFactory.getLog(EventPublishingRunListener.class); @Override public void handleError (Throwable throwable ) { logger.warn("Error calling ApplicationEventListener" , throwable); } } }
可以看到EventPublishingRunListener
类实现了SpringApplicationRunListener
接口,SpringApplicationRunListener
接口定义了SpringBoot启动时触发生命周期事件的接口方法,而EventPublishingRunListener
类正是通过实现SpringApplicationRunListener
接口的starting
,environmentPrepared
和contextPrepared
等方法来广播SpringBoot不同的生命周期事件,直接看下SpringApplicationRunListener
接口源码好了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 public interface SpringApplicationRunListener { void starting(); void environmentPrepared(ConfigurableEnvironment environment); void contextPrepared(ConfigurableApplicationContext context); void contextLoaded(ConfigurableApplicationContext context); void started(ConfigurableApplicationContext context); void running(ConfigurableApplicationContext context); void failed(ConfigurableApplicationContext context, Throwable exception ); }
再接着分析EventPublishingRunListener
这个类,可以看到其有一个重要的成员属性initialMulticaster
,该成员属性是SimpleApplicationEventMulticaster
类对象,该类正是承担了广播SpringBoot启动时生命周期事件的职责,即EventPublishingRunListener
对象没有承担广播事件的职责,而最终是委托SimpleApplicationEventMulticaster
来广播事件的。
从EventPublishingRunListener
的源码中也可以看到在starting
,environmentPrepared
和contextPrepared
等方法中也正是通过调用SimpleApplicationEventMulticaster
类对象的multicastEvent
方法来广播事件的。
思考 SpringBoot启动过程中触发事件时事件广播者是层层委托职责的,起初由SpringApplicationRunListeners
对象承担,然后SpringApplicationRunListeners
对象将广播事件职责委托给EventPublishingRunListener
对象,最终EventPublishingRunListener
对象将广播事件的职责委托给SimpleApplicationEventMulticaster
对象。为什么要层层委托这么做呢?
前面讲到从spring.factories
中加载出EventPublishingRunListener
类后会实例化,而实例化必然会通过EventPublishingRunListener
的构造函数来进行实例化,接下来分析下EventPublishingRunListener
的构造函数源码:
1 2 3 4 5 6 7 8 9 10 11 public EventPublishingRunListener(SpringApplication application, String[] args) { this .application = application; this .args = args; this .initialMulticaster = new SimpleApplicationEventMulticaster(); for (ApplicationListener<?> listener : application.getListeners()) { this .initialMulticaster.addApplicationListener(listener); } }
可以看到在EventPublishingRunListener
的构造函数中有一个for
循环会遍历之前从spring.factories
中加载的监听器们,然后添加到集合中缓存起来,用于以后广播各种事件时直接从这个集合中取出来即可,而不用再去spring.factories
中加载,提高效率。
1.2 广播SpringBoot的内置生命周期事件 从spring.factories
配置文件中加载并实例化EventPublishingRunListener
对象后,那么在SpringBoot的启动过程中会触发一系列SpringBoot内置的生命周期事件,从以上SpringBoot启动过程中的源码,可以看到在SpringBoot的启动过程中总共会触发7种不同类型的生命周期事件,来标志SpringBoot的不同启动阶段,同时,这些生命周期事件的监听器也会执行一些启动过程中的初始化逻辑。
以下是SpringBoot启动过程中要触发的事件类型,其中ApplicationFailedEvent
在SpringBoot启动过程中遇到异常才会触发:
ApplicationStartingEvent
ApplicationEnvironmentPreparedEvent
ApplicationContextInitializedEvent
ApplicationPreparedEvent
ApplicationStartedEvent
ApplicationFailedEvent
ApplicationReadyEvent
以listeners.starting();
这句代码为例,看看EventPublishingRunListener
对象触发事件的源码:
1 2 3 4 5 6 7 8 public void starting ( ) { for (SpringApplicationRunListener listener : this .listeners) { listener.starting(); } }
继续跟进listener.starting();
的源码:
1 2 3 4 5 6 7 @Override public void starting ( ) { this .initialMulticaster.multicastEvent(new ApplicationStartingEvent(this .application, this .args)); }
可以看到,EventPublishingRunListener
对象将发布ApplicationStartingEvent
这件事情委托给了SimpleApplicationEventMulticaster
对象initialMulticaster
, ,而initialMulticaster
对象最终会调用其multicastEvent
方法来触发ApplicationStartingEvent
事件。
2.SpringBoot的内置生命周期事件总结 SpringBoot启动过程中要触发的各种生命周期事件
发布顺序
时间
用途
1
ApplicationStartingEvent
在SpringApplication启动时,在环境变量Environment或者容器ApplicationContext创建前触发,标志SpringApplication开始启动。
2
ApplicationEnvironmentPreparedEvent
当SpringApplication已经开始启动且环境变量Environment已经准备好时触发,标志环境变量已经准备好。
3
ApplicationContextInitializedEvent
ApplicationContextInitializers的初始化方法已经被调用,即从spring.factories中加载的initializers已经执行ApplicationContext初始化逻辑但在bean定义加载前触发,标志ApplicationContext已经初始化完毕。
4
ApplicationPreparedEvent
在Spring容器刷新refresh前触发
5
ApplicationStartedEvent
在spring容器刷新后触发,但在调用ApplicationRunner和CommandLineRunner的run方法调用前触发,标志spring容器已经刷新,此时所有的bean实例等都已经加载了。
6
ApplicationReadyEvent
只要SpringApplication可以接收服务请求时即调用完ApplicationRunner和CommandLineRunner的run方法后触发,此时标志SpringApplication已经正在运行,即启动成功。
7
ApplicationFailedEvent
若SpringApplication未能成功启动时则会catch住异常发布ApplicationFailedEvent事件,标志ApplicationFailedEvent启动失败。
总结 SpringBoot启动过程中会触发7种类型的生命周期事件,标志不同的启动阶段,然后相应的监听器会监听这些事件来执行一些初始化逻辑工作。
评论加载中