監(jiān)聽(tīng)器模式

監(jiān)聽(tīng)器模式有要素
- 事件
- 監(jiān)聽(tīng)器
- 廣播器
- 觸發(fā)機(jī)制
系統(tǒng)監(jiān)聽(tīng)器
監(jiān)聽(tīng)器 ApplicationListener
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
/**
* Handle an application event.
* @param event the event to respond to
*/
void onApplicationEvent(E event);
}
FunctionalInterface是jdk8新增的,表示ApplicationListener接口只有一個(gè)方法,如果大于一個(gè)方法,就不能使用這注解
接口中有個(gè)泛型<E extends ApplicationEvent>,繼承自ApplicationEvent。就代表這實(shí)現(xiàn)這個(gè)接口時(shí),可以聲明對(duì)哪些事件(如ApplicationEvent)感興趣,在觸發(fā)監(jiān)聽(tīng)器的時(shí)候,對(duì)感興趣的事件進(jìn)行過(guò)濾。
系統(tǒng)廣播器ApplicationEventMulticaster接口
public interface ApplicationEventMulticaster {
void addApplicationListener(ApplicationListener<?> listener);
void addApplicationListenerBean(String listenerBeanName);
void removeApplicationListener(ApplicationListener<?> listener);
void removeApplicationListenerBean(String listenerBeanName);
void removeAllListeners();
void multicastEvent(ApplicationEvent event);
void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);
}
ApplicationEventMulticaster接口主要有三類方法,增加監(jiān)聽(tīng)器,刪除監(jiān)聽(tīng)器,廣播方法
系統(tǒng)事件,SpringBoot框架事件

SpringBoot中的事件發(fā)送順序

注冊(cè)監(jiān)聽(tīng)器(Listener)
public class SpringApplication {
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();
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
//設(shè)置監(jiān)聽(tīng)器
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = this.deduceMainApplicationClass();
}
}
我們還是跟進(jìn)代碼看看getSpringFactoriesInstances
public class SpringApplication {
// 這里的入?yún)ype是:org.springframework.context.ApplicationListener.class
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return this.getSpringFactoriesInstances(type, new Class[0]);
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = this.getClassLoader();
Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
}
可以發(fā)現(xiàn),這個(gè)加載相應(yīng)的類名,然后完成實(shí)例化的過(guò)程和上面在設(shè)置初始化器時(shí)如出一轍,同樣,還是以spring-boot-autoconfigure這個(gè)包中的spring.factories為例,看看相應(yīng)的Key-Value:
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer
# Application Listeners
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
這10個(gè)監(jiān)聽(tīng)器會(huì)貫穿springBoot整個(gè)生命周期。至此,對(duì)于SpringApplication實(shí)例的初始化過(guò)程就結(jié)束了。

完成了SpringApplication實(shí)例化,下面開(kāi)始調(diào)用run方法:
public ConfigurableApplicationContext run(String... args) {
// 計(jì)時(shí)工具
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
this.configureHeadlessProperty();
// 第一步:獲取并啟動(dòng)監(jiān)聽(tīng)器
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting();
Collection exceptionReporters;
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 第二步:根據(jù)SpringApplicationRunListeners以及參數(shù)來(lái)準(zhǔn)備環(huán)境
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
this.configureIgnoreBeanInfo(environment);
// 準(zhǔn)備Banner打印器 - 就是啟動(dòng)Spring Boot的時(shí)候打印在console上的ASCII藝術(shù)字體
Banner printedBanner = this.printBanner(environment);
// 第三步:創(chuàng)建Spring容器
context = this.createApplicationContext();
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
// 第四步:Spring容器前置處理
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 第五步:刷新容器
this.refreshContext(context);
// 第六步:Spring容器后置處理
this.afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
// 第七步:發(fā)出結(jié)束執(zhí)行的事件
listeners.started(context);
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}
try {
// 第八步:執(zhí)行Runners
listeners.running(context);
// 返回容器
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
- 第一步:獲取并啟動(dòng)監(jiān)聽(tīng)器
- 第二步:根據(jù)SpringApplicationRunListeners以及參數(shù)來(lái)準(zhǔn)備環(huán)境
- 第三步:創(chuàng)建Spring容器
- 第四步:Spring容器前置處理
- 第五步:刷新容器
- 第六步:Spring容器后置處理
- 第七步:發(fā)出結(jié)束執(zhí)行的事件
- 第八步:執(zhí)行Runners
這里主要分析監(jiān)聽(tīng)器相關(guān)的步驟
第一步:獲取并啟動(dòng)監(jiān)聽(tīng)器
獲取監(jiān)聽(tīng)器
跟進(jìn)getRunListeners方法:
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
這里仍然利用了getSpringFactoriesInstances方法來(lái)獲取實(shí)例,大家可以看看前面的這個(gè)方法分析,從META-INF/spring.factories中讀取Key為org.springframework.boot.SpringApplicationRunListener的Values:
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
getSpringFactoriesInstances中反射獲取實(shí)例時(shí)會(huì)觸發(fā)EventPublishingRunListener的構(gòu)造函數(shù),我們來(lái)看看EventPublishingRunListener的構(gòu)造函數(shù):
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();
Iterator var3 = application.getListeners().iterator();
while(var3.hasNext()) {
ApplicationListener<?> listener = (ApplicationListener)var3.next();
//將上面設(shè)置到SpringApplication的十一個(gè)監(jiān)聽(tīng)器全部添加到SimpleApplicationEventMulticaster這個(gè)廣播器中
this.initialMulticaster.addApplicationListener(listener);
}
}
......
}
我們看到EventPublishingRunListener里面有一個(gè)廣播器,EventPublishingRunListener 的構(gòu)造方法將SpringApplication的十一個(gè)監(jiān)聽(tīng)器全部添加到SimpleApplicationEventMulticaster這個(gè)廣播器中,我們來(lái)看看是如何添加到廣播器:
public abstract class AbstractApplicationEventMulticaster
implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {
//廣播器的父類中存放保存監(jiān)聽(tīng)器的內(nèi)部?jī)?nèi)
private final ListenerRetriever defaultRetriever = new ListenerRetriever(false);
......
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
synchronized (this.retrievalMutex) {
// Explicitly remove target for a proxy, if registered already,
// in order to avoid double invocations of the same listener.
Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
if (singletonTarget instanceof ApplicationListener) {
this.defaultRetriever.applicationListeners.remove(singletonTarget);
}
//內(nèi)部類對(duì)象
this.defaultRetriever.applicationListeners.add(listener);
this.retrieverCache.clear();
}
}
private class ListenerRetriever {
//保存所有的監(jiān)聽(tīng)器
public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();
public final Set<String> applicationListenerBeans = new LinkedHashSet<>();
private final boolean preFiltered;
public ListenerRetriever(boolean preFiltered) {
this.preFiltered = preFiltered;
}
public Collection<ApplicationListener<?>> getApplicationListeners() {
List<ApplicationListener<?>> allListeners = new ArrayList<>(
this.applicationListeners.size() + this.applicationListenerBeans.size());
allListeners.addAll(this.applicationListeners);
if (!this.applicationListenerBeans.isEmpty()) {
BeanFactory beanFactory = getBeanFactory();
for (String listenerBeanName : this.applicationListenerBeans) {
try {
ApplicationListener<?> listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class);
if (this.preFiltered || !allListeners.contains(listener)) {
allListeners.add(listener);
}
}
catch (NoSuchBeanDefinitionException ex) {
// Singleton listener instance (without backing bean definition) disappeared -
// probably in the middle of the destruction phase
}
}
}
if (!this.preFiltered || !this.applicationListenerBeans.isEmpty()) {
AnnotationAwareOrderComparator.sort(allListeners);
}
return allListeners;
}
}
}
上述方法定義在SimpleApplicationEventMulticaster父類AbstractApplicationEventMulticaster中。關(guān)鍵代碼為this.defaultRetriever.applicationListeners.add(listener);,這是一個(gè)內(nèi)部類,用來(lái)保存所有的監(jiān)聽(tīng)器。也就是在這一步,將spring.factories中的監(jiān)聽(tīng)器傳遞到SimpleApplicationEventMulticaster中。我們現(xiàn)在知道EventPublishingRunListener中有一個(gè)廣播器SimpleApplicationEventMulticaster,SimpleApplicationEventMulticaster廣播器中又存放所有的監(jiān)聽(tīng)器。
啟動(dòng)監(jiān)聽(tīng)器
我們上面一步通過(guò)getRunListeners方法獲取的監(jiān)聽(tīng)器為EventPublishingRunListener,從名字可以看出是啟動(dòng)事件發(fā)布監(jiān)聽(tīng)器,主要用來(lái)發(fā)布啟動(dòng)事件。
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
private final SpringApplication application;
private final String[] args;
private final SimpleApplicationEventMulticaster initialMulticaster;
我們先來(lái)看看SpringApplicationRunListener這個(gè)接口
public interface SpringApplicationRunListener {
// 在run()方法開(kāi)始執(zhí)行時(shí),該方法就立即被調(diào)用,可用于在初始化最早期時(shí)做一些工作
void starting();
// 當(dāng)environment構(gòu)建完成,ApplicationContext創(chuàng)建之前,該方法被調(diào)用
void environmentPrepared(ConfigurableEnvironment environment);
// 當(dāng)ApplicationContext構(gòu)建完成時(shí),該方法被調(diào)用
void contextPrepared(ConfigurableApplicationContext context);
// 在ApplicationContext完成加載,但沒(méi)有被刷新前,該方法被調(diào)用
void contextLoaded(ConfigurableApplicationContext context);
// 在ApplicationContext刷新并啟動(dòng)后,CommandLineRunners和ApplicationRunner未被調(diào)用前,該方法被調(diào)用
void started(ConfigurableApplicationContext context);
// 在run()方法執(zhí)行完成前該方法被調(diào)用
void running(ConfigurableApplicationContext context);
// 當(dāng)應(yīng)用運(yùn)行出錯(cuò)時(shí)該方法被調(diào)用
void failed(ConfigurableApplicationContext context, Throwable exception);
}
SpringApplicationRunListener接口在Spring Boot 啟動(dòng)初始化的過(guò)程中各種狀態(tài)時(shí)執(zhí)行,我們也可以添加自己的監(jiān)聽(tīng)器,在SpringBoot初始化時(shí)監(jiān)聽(tīng)事件執(zhí)行自定義邏輯,我們先來(lái)看看SpringBoot啟動(dòng)時(shí)第一個(gè)啟動(dòng)事件listeners.starting():
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
public void starting() {
//關(guān)鍵代碼,先創(chuàng)建application啟動(dòng)事件`ApplicationStartingEvent`
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
}
這里先創(chuàng)建了一個(gè)啟動(dòng)事件ApplicationStartingEvent,我們繼續(xù)跟進(jìn)SimpleApplicationEventMulticaster,有個(gè)核心方法:
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
@Override
public void multicastEvent(ApplicationEvent event) {
multicastEvent(event, resolveDefaultEventType(event));
}
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
//獲取線程池,如果為空則同步處理。這里線程池為空,還未沒(méi)初始化。
Executor executor = getTaskExecutor();
//通過(guò)事件類型ApplicationStartingEvent獲取對(duì)應(yīng)的監(jiān)聽(tīng)器
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
//異步發(fā)送事件
executor.execute(() -> invokeListener(listener, event));
}
else {
//同步發(fā)送事件
invokeListener(listener, event);
}
}
}
}
這里會(huì)根據(jù)事件類型ApplicationStartingEvent獲取對(duì)應(yīng)的監(jiān)聽(tīng)器,在容器啟動(dòng)之后執(zhí)行響應(yīng)的動(dòng)作,有如下4種監(jiān)聽(tīng)器:

public class LoggingApplicationListener implements GenericApplicationListener {
public void onApplicationEvent(ApplicationEvent event) {
//在springboot啟動(dòng)的時(shí)候
if (event instanceof ApplicationStartingEvent) {
this.onApplicationStartingEvent((ApplicationStartingEvent)event);
//springboot的Environment環(huán)境準(zhǔn)備完成的時(shí)候
} else if (event instanceof ApplicationEnvironmentPreparedEvent) {
this.onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent)event);
//在springboot容器的環(huán)境設(shè)置完成以后
} else if (event instanceof ApplicationPreparedEvent) {
this.onApplicationPreparedEvent((ApplicationPreparedEvent)event);
//容器關(guān)閉的時(shí)候
} else if (event instanceof ContextClosedEvent && ((ContextClosedEvent)event).getApplicationContext().getParent() == null) {
this.onContextClosedEvent();
//容器啟動(dòng)失敗的時(shí)候
} else if (event instanceof ApplicationFailedEvent) {
this.onApplicationFailedEvent();
}
}
}
因?yàn)槲覀兊氖录愋蜑锳pplicationEvent,所以會(huì)執(zhí)行onApplicationStartedEvent((ApplicationStartedEvent) event);。springBoot會(huì)在運(yùn)行過(guò)程中的不同階段,發(fā)送各種事件,來(lái)執(zhí)行對(duì)應(yīng)監(jiān)聽(tīng)器的對(duì)應(yīng)方法。
第二步:環(huán)境構(gòu)建
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
跟進(jìn)去該方法:
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
//獲取對(duì)應(yīng)的ConfigurableEnvironment
ConfigurableEnvironment environment = this.getOrCreateEnvironment();
//配置
this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach((Environment)environment);
//發(fā)布環(huán)境已準(zhǔn)備事件,這是第二次發(fā)布事件
listeners.environmentPrepared((ConfigurableEnvironment)environment);
this.bindToSpringApplication((ConfigurableEnvironment)environment);
if (!this.isCustomEnvironment) {
environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
}
ConfigurationPropertySources.attach((Environment)environment);
return (ConfigurableEnvironment)environment;
}
來(lái)看一下getOrCreateEnvironment()方法,前面已經(jīng)提到,environment已經(jīng)被設(shè)置了servlet類型,所以這里創(chuàng)建的是環(huán)境對(duì)象是StandardServletEnvironment。
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
} else {
switch(this.webApplicationType) {
case SERVLET:
return new StandardServletEnvironment();
case REACTIVE:
return new StandardReactiveWebEnvironment();
default:
return new StandardEnvironment();
}
}
}
接下來(lái)看一下listeners.environmentPrepared(environment);,上面已經(jīng)提到了,這里是第二次發(fā)布事件。什么事件呢?來(lái)看一下根據(jù)事件類型獲取到的監(jiān)聽(tīng)器:

主要來(lái)看一下ConfigFileApplicationListener,該監(jiān)聽(tīng)器非常核心,主要用來(lái)處理項(xiàng)目配置。項(xiàng)目中的 properties 和yml文件都是其內(nèi)部類所加載。具體來(lái)看一下:

首先還是會(huì)去讀spring.factories 文件,List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();獲取的處理類有以下四種:
# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,\
org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor
在執(zhí)行完上述三個(gè)監(jiān)聽(tīng)器流程后,ConfigFileApplicationListener會(huì)執(zhí)行該類本身的邏輯。由其內(nèi)部類Loader加載項(xiàng)目制定路徑下的配置文件:
private static final String DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/";
至此,項(xiàng)目的變量配置已全部加載完畢,來(lái)一起看一下:

這里一共7個(gè)配置文件,取值順序由上到下。也就是說(shuō)前面的配置變量會(huì)覆蓋后面同名的配置變量。項(xiàng)目配置變量的時(shí)候需要注意這點(diǎn)。
監(jiān)聽(tīng)事件觸發(fā)機(jī)制
獲取監(jiān)聽(tīng)器列表

通用觸發(fā)條件

自定義監(jiān)聽(tīng)器
實(shí)現(xiàn)方式一
- 1、實(shí)現(xiàn)ApplicationListener接口
@Order(1)
public class Listener1 implements ApplicationListener<ApplicationStartedEvent> {
@Override
public void onApplicationEvent(ApplicationStartedEvent event) {
System.out.println("hello Listener1");
}
}
- 2、利用SPI機(jī)制在META-INF/spring.factories中添加配置項(xiàng)進(jìn)行注冊(cè)
org.springframework.context.ApplicationListener=com.yibo.source.code.listener.Listener1
實(shí)現(xiàn)方式二
- 1、實(shí)現(xiàn)ApplicationListener接口
@Order(2)
public class Listener2 implements ApplicationListener<ApplicationStartedEvent> {
@Override
public void onApplicationEvent(ApplicationStartedEvent event) {
System.out.println("hello Listener2");
}
}
- 2、SpringApplication初始化后設(shè)置進(jìn)去
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(Application.class);
springApplication.addListeners(new Listener2());
springApplication.run();
}
}
實(shí)現(xiàn)方式三
- 1、實(shí)現(xiàn)ApplicationListener接口
@Order(3)
public class Listener3 implements ApplicationListener<ApplicationStartedEvent> {
@Override
public void onApplicationEvent(ApplicationStartedEvent event) {
System.out.println("hello Listener3");
}
}
- 2、appplication.properties內(nèi)填寫接口實(shí)現(xiàn)
context.listener.classes=com.yibo.source.code.listener.Listener3
實(shí)現(xiàn)方式四
- 1、實(shí)現(xiàn)SmartApplicationListener接口
@Order(4)
public class Listener4 implements SmartApplicationListener{
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return ApplicationStartedEvent.class.isAssignableFrom(eventType) ||
ApplicationPreparedEvent.class.isAssignableFrom(eventType);
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("hello Listener4");
}
}
- 2、需要重寫supportsEventType方法
- 3、使用前三種方式注入框架
總結(jié)
- 1、實(shí)現(xiàn)ApplicationListener接口針對(duì)單一事件監(jiān)聽(tīng)
- 2、實(shí)現(xiàn)SmartApplicationListener接口針對(duì)多種事件監(jiān)聽(tīng)
- 3、Order值越小越先執(zhí)行
- 4、application.properties中定義的優(yōu)于其他方式