Spring Event(Application Event)其实就是一个观察者模式。观察者模式含有主题(针对该主题的事件ApplicationEvent)、发布者、订阅者/监听器。ApplicationEventMulticaster:事件管理者,用于事件监听器的注册和事件的广播。ApplicationEventPublisher:事件发布者,委托ApplicationEventMulticaster完成事件的发布。
SpringBoot根据监听器加载方式主要分为两种:
- Spi机制加载得到的。当然用户也可以按照SPI机制规范使用该类型下的监听器。
- 自定义IOC容器托管bean的方式。
针对第一种方式:SpringBoot在启动过程中主要存在两种不同类型的监听器即ApplicationListener
、SpringApplicationRunListener
,这两种监听器都是通过SPI机制得到具体的实现类。
第二种方式:实际使用过程中更多选择ApplicationEventPublisherAware
类型的事件发布者实现事件发布机制功能。
SpringBoot根据监听器事件监听触发的时机又分为很多种:
- 在刷新容器refresh之前存在一部分事件发布机制,一般是指SPI机制加载得到的监听器。
- 在刷新容器refresh过程中,不同时间节点也存在相应的事件发布机制。
- 容器被刷新完之后,例如最常见的
ContextRefreshedEvent
类型事件。
不管监听器是何种加载方式,最终都是由 SimpleApplicationEventMulticaster
触发事件的监听。
SpringBoot内部获取监听器方式存在两种:直接获取全部监听器、根据事件类型获取对应的监听器。这些监听器在SpringBoot应用中可能随着启动流程被触发一次或者多次,主要是根据监听器支持的事件类型决定的。如果选择ApplicationEventPublisherAware实现事件发布者机制则事件触发时机完全取决于web请求。
1.SpringApplicationRunListener
SpringApplicationRunListener接口中相关事件贯穿于Spring启动的整个流程。这个接口的具体实现类除了Spring内置类EventPublishingRunListener
,用于也可以自定义该类型的监听器,参与控制Spring启动的整个流程。
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);
}
具体参考:SpringApplicationRunListeners。
1.1.发布者之EventPublishingRunListener
接口SpringApplicationRunListener不同方法其实对应不同的事件。不同事件的触发最终是被委托给EventPublishingRunListener完成的,其中分别对应ApplicationStartingEvent、ApplicationEnvironmentPreparedEvent、ApplicationContextInitializedEvent、ApplicationPreparedEvent、ApplicationStartedEvent、ApplicationReadyEvent、ApplicationFailedEvent事件类型。这些类型的事件穿插在Spring机制中不同结点处。
其实在当前监听器内部事件的真正发布又一次发生了委托,真正委托对象为SimpleApplicationEventMulticaster
。
1.1.1.监听器之ApplicationListener
public class SpringApplication {
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
...
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//初始化提前约定的全部监听器【约定大于配置】
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
}
}
利用类加载器加载classpath特定路径【META-INF/spring.factories】下存在的 ApplicationListener 监听器的实现子类。
spring-boot.jar#spring.factories文件:
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
# 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
该类型的监听器存在顶级子接口GenericApplicationListener、SmartApplicationListener。这俩接口内部支持监听器ApplicationListener订阅特定类型的事件ApplicationEvent。
SimpleApplicationEventMulticaster作为真正事件发布者,其实是触发相应类型的事件监听器ApplicationListener执行特定的事件。
2.earlyApplicationEvents事件发布机制
earlyApplicationEvents字面意思是指需要及早触发的事件机制。这个“早”是指在IOC注册表中的bean实例化之前就需要触发的事件类型。
public abstract class AbstractApplicationContext{
private Set<ApplicationEvent> earlyApplicationEvents;
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
prepareRefresh();// 初始化变量 earlyApplicationEvents
...
prepareBeanFactory(beanFactory);
postProcessBeanFactory(beanFactory);
invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);
...
registerListeners();// 触发集合earlyApplicationEvents中所有事件
finishBeanFactoryInitialization(beanFactory);
finishRefresh();
}
}
// earlyApplicationEvents集合中添加 需要及早触发的事件
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
...
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}else {
// 发布者添加事件后马上出发监听器执行
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
...
}
protected void registerListeners() {
// 获取SPI机制获取到的监听器
for (ApplicationListener<?> listener : getApplicationListeners()) {
// 将SPI机制获取到的监听器维护起来
getApplicationEventMulticaster().addApplicationListener(listener);
}
// 从IOC容器中获取ApplicationListener类型的事件监听器。此处步骤可以促使当前监听器提早实例化、初始化
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
// 将候选事件监听器维护起来
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// 当然对于自定义的事件类型必须显式添加到集合属性earlyApplicationEvents
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
// 从所有监听器中选出支持集合earlyEventsToProcess中事件类型的监听器,并直接触发监听机制执行
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
}
AbstractApplicationContext是ApplicationEventPublisher
接口的子类,所以也是具有发布者功能的。在其内部事件的发布存在两种形式:
- 如果是在
registerListeners
之前就触发事件的发布,则这种类型的事件最终作为earlyApplicationEvents类型事件处理。 - 如果是在运行期触发事件的发布,则事件发布之时立即触发对应监听器监听事件。例如
ApplicationEventPublisherAware
实现的运行时发布者机制。
3.ApplicationEventPublisherAware
该类实现的事件发布机制其触发时机完全取决于web请求。具体触发流程参考AbstractApplicationContext集合earlyApplicationEvents中对应的事件类型执行流程。
class ApplicationContextAwareProcessor implements BeanPostProcessor {
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
...
if (bean instanceof ApplicationEventPublisherAware) {//回调设置ApplicationEventPublisher
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
...
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
}
ApplicationEventPublisher其实就是AbstractApplicationContext【本身就是发布者】。
4.ContextRefreshedEvent事件
Spring IOC容器就绪之后,框架将触发全部监听器处理ContextRefreshedEvent事件。
public abstract class AbstractApplicationContext{
private Set<ApplicationEvent> earlyApplicationEvents;
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
...
prepareBeanFactory(beanFactory);
postProcessBeanFactory(beanFactory);
invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);
...
registerListeners();
finishBeanFactoryInitialization(beanFactory);
finishRefresh();//触发ContextRefreshedEvent事件
}
}
}
Dubbo中DubboDeployApplicationListener监听器就会处理该事件。
判断支持的事件类型
public abstract class AbstractApplicationEventMulticaster{
private boolean supportsEvent(ConfigurableBeanFactory bf, String listenerBeanName, ResolvableType eventType) {
Class<?> listenerType = bf.getType(listenerBeanName);
// 如果监听器是GenericApplicationListener或者SmartApplicationListener类型,则支持全部的事件类型
if (listenerType == null || GenericApplicationListener.class.isAssignableFrom(listenerType) ||
SmartApplicationListener.class.isAssignableFrom(listenerType)) {
return true;
}
// 如果监听器支持的事件类型与当前eventType事件类型一致或者当前事件类型eventType是监听器支持事件类型的子类
if (!supportsEvent(listenerType, eventType)) {
return false;
}
BeanDefinition bd = bf.getMergedBeanDefinition(listenerBeanName);
//获取接口ApplicationListener的泛型之ApplicationEvent
ResolvableType genericEventType = bd.getResolvableType().as(ApplicationListener.class).getGeneric();
// 如果监听器监听的事件为基本事件类型ApplicationEvent或者ApplicationEvent其子类,则当前监听器处理全部事件类型
return (genericEventType == ResolvableType.NONE || genericEventType.isAssignableFrom(eventType));
}
}