大家都知道,在 Spring 框架中事件和监听无处不在,打通了 Spring 框架的任督二脉,事件和监听也是 Spring 框架必学的核心知识之一。
一般来说,我们很少会使用到应用程序事件,但我们也不要忘了它们的存在,比如说在 Spring 框架内部都使用了各种不同的事件来处理不同的任务。
毫无疑问,在 Spring Boot 框架中,事件和监听也得到了发扬光大,除了常用的 Spring Framework 事件(例如:ContextRefreshedEvent)之外,Spring Boot 在启动过程中还发送一系列其他的应用程序事件。
Spring Boot 启动事件顺序
1、ApplicationStartingEvent
这个事件在 Spring Boot 应用运行开始时,且进行任何处理之前发送(除了监听器和初始化器注册之外)。
2、ApplicationEnvironmentPreparedEvent
这个事件在当已知要在上下文中使用 Spring 环境(Environment)时,在 Spring 上下文(context)创建之前发送。
3、ApplicationContextInitializedEvent
这个事件在当 Spring 应用上下文(ApplicationContext)准备好了,并且应用初始化器(ApplicationContextInitializers)已经被调用,在 bean 的定义(bean definitions)被加载之前发送。
4、ApplicationPreparedEvent
这个事件是在 Spring 上下文(context)刷新之前,且在 bean 的定义(bean definitions)被加载之后发送。
5、ApplicationStartedEvent
这个事件是在 Spring 上下文(context)刷新之后,且在 application/ command-line runners 被调用之前发送。
6、AvailabilityChangeEvent
这个事件紧随上个事件之后发送,状态:ReadinessState.CORRECT,表示应用已处于活动状态。
7、ApplicationReadyEvent
这个事件在任何 application/ command-line runners 调用之后发送。
8、AvailabilityChangeEvent
这个事件紧随上个事件之后发送,状态:ReadinessState.ACCEPTING_TRAFFIC,表示应用可以开始准备接收请求了。
9、ApplicationFailedEvent
这个事件在应用启动异常时进行发送。
上面所介绍的这些事件列表仅包括绑定到 SpringApplication 的 SpringApplicationEvents 事件,除了这些事件以外,以下事件也会在 ApplicationPreparedEvent 之后和 ApplicationStartedEvent 之前发送:
- WebServerInitializedEvent
这个 Web 服务器初始化事件在 WebServer 启动之后发送,对应的还有 ServletWebServerInitializedEvent(Servlet Web 服务器初始化事件)、ReactiveWebServerInitializedEvent(响应式 Web 服务器初始化事件)。 - ContextRefreshedEvent
这个上下文刷新事件是在 Spring 应用上下文(ApplicationContext)刷新之后发送。
自定义启动事件监听器
既然我们知道了 Spring Boot 在启动过程中的各个事件,那么我们就可以在每个环节来处理一些我们想做的事情,只需要自定义一个监听器来监听某个事件就可以了。
比如我们想在上面的第 8 步,即应用启动完成可以接收请求了,我们简单输出一个成功标识。
1、新建监听器
import lombok.extern.slf4j.Slf4j;import org.springframework.boot.availability.AvailabilityChangeEvent;import org.springframework.boot.availability.ReadinessState;import org.springframework.context.ApplicationListener;/*** 来源:Java技术栈*/@Slf4jpublic class JavastackListener implements ApplicationListener<AvailabilityChangeEvent> {@Overridepublic void onApplicationEvent(AvailabilityChangeEvent event) {log.info("监听到事件:" + event);if (ReadinessState.ACCEPTING_TRAFFIC == event.getState()){log.info("应用启动完成,可以请求了……");}}}
新建一个自定义监听器,实现了 ApplicationListener 接口,泛型 AvailabilityChangeEvent 表示仅仅监听 AvailabilityChangeEvent 事件。
因第 8 步的事件和第 6 步的事件同名,我们可以根据事件的状态来区分到底是哪一个环节的事件 。
2、注册监听器
注册监听器有两种方式:
1、在资源目录中的 META-INF/spring.factories 文件中自动注册:
org.springframework.context.ApplicationListener=\
cn.javastack.springboot.features.listener.JavastackListener
2、如果是监听 Spring 应用上下文(ApplicationContext)创建之后的事件,可以直接在监听器上使用 @Component 注解即可,否则需要使用第一种方法的自动注册,因为 ApplicationContext 并未创建,这时的 Bean 是不能被加载的。
3、应用启动
下面来看下启动日志:
可以看到同时输出了第 6 步和 8 步的监听日志,但只输出第 8 步的启动完成日志,自定义监听实现成功。
总结
了解了 Spring Boot 启动过程中的各个事件及监听机制,大家可以依葫芦画瓢实现 Spring Boot 启动过程中的各个自定义操作,比如说在启动过程上实现动态注册、移除 Bean 等。
一般来说,不建议使用事件和监听器来实现比较耗时和繁重的任务,这样会影响应用程序的正常启动,考虑使用 Spring Boot 的 application/ command-line runners 来进行实现。
系统事件
| 事件名 | 作用 |
|---|---|
| ApplicationStartingEvent | 框架启动事件 |
| ApplicationEnvironmentPreparedEvent | 环境准备完毕事件 |
| ApplicationContextInitializedEvent | 上下文初始化 |
| ApplicationPreparedEvent | 上下文创建完毕,但是Bean还没有加载完毕 |
| ApplicationStartedEvent | bean 实例化完成,但是未调用 Runners接口 |
| ApplicationReadyEvent | 调用 Runners 接口完毕 |
| ApplicationFailedEvent | 启动失败事件 |
3.4 监听器注册
在 SpringApplication 初始化的时候就进行了监听器注册
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
......
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
......
}
3.5 监听器事件触发机制
在springBoot 的中的执行顺序
public ConfigurableApplicationContext run(String... args) {
// ApplicationStartingEvent
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
// ApplicationEnvironmentPreparedEvent
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
// 上下文加载之前ApplicationContextInitializedEvent
// 上下文加载完成ApplicationPreparedEvent
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
// ApplicationStartedEvent
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
// ApplicationFailedEvent
handleRunFailure(context, ex, exceptionReporters, listeners);
}
// ApplicationReadyEvent
listeners.running(context);
return context;
}
以 starting 事件为例
public ConfigurableApplicationContext run(String... args) {
......
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
......
}
进入 starting 方法,里面是遍历所有的 SpringApplicationRunListeners:
void starting() {
for (SpringApplicationRunListener listener : this.listeners) {
listener.starting();
}
}
SpringApplicationRunListeners 接口定义如下,可以看到申明了多个事件:
public interface SpringApplicationRunListener {
default void starting() {}
default void environmentPrepared(ConfigurableEnvironment environment) {}
default void contextPrepared(ConfigurableApplicationContext context) {}
default void contextLoaded(ConfigurableApplicationContext context) {}
default void started(ConfigurableApplicationContext context) {}
default void running(ConfigurableApplicationContext context) {}
default void failed(ConfigurableApplicationContext context, Throwable exception){}
}
看下默认的实现类 EventPublishingRunListener:
public class EventPublishingRunListener{
......
private final SimpleApplicationEventMulticaster initialMulticaster;
@Override
public void starting() {
// 调用广播器来发送事件
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
......
}
进入 multicastEvent 方法
@Override
public void multicastEvent(ApplicationEvent event) {
multicastEvent(event, resolveDefaultEventType(event));
}
resolveDefaultEventType 是对 event 的包装,不需要理会。
private ResolvableType resolveDefaultEventType(ApplicationEvent event) {
return ResolvableType.forInstance(event);
}
回到 multicastEvent 方法
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
// 获得线程池
Executor executor = getTaskExecutor();
// getApplicationListeners --> 获得对当前event感兴趣的监听器列表
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
获得对当前 event 感兴趣的监听器列表:
protected Collection<ApplicationListener<?>> getApplicationListeners(
ApplicationEvent event, ResolvableType eventType) {
// 获取事件来源,这里的 source 就是 SpringApplication
Object source = event.getSource();
Class<?> sourceType = (source != null ? source.getClass() : null);
ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
// 从缓存中获取结果
ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
if (retriever != null) {
return retriever.getApplicationListeners();
}
if (this.beanClassLoader == null ||
(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
// 完全同步构建和缓存ListenerRetriever
synchronized (this.retrievalMutex) {
retriever = this.retrieverCache.get(cacheKey);
if (retriever != null) {
return retriever.getApplicationListeners();
}
retriever = new ListenerRetriever(true);
// 检索感兴趣的监听器
Collection<ApplicationListener<?>> listeners =
retrieveApplicationListeners(eventType, sourceType, retriever);
// 存放到缓存中
this.retrieverCache.put(cacheKey, retriever);
return listeners;
}
}
else {
// 无需 ListenerRetriever 缓存->无需同步
return retrieveApplicationListeners(eventType, sourceType, null);
}
}
检索感兴趣的监听器实现:
private Collection<ApplicationListener<?>> retrieveApplicationListeners(
ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable ListenerRetriever retriever) {
List<ApplicationListener<?>> allListeners = new ArrayList<>();
Set<ApplicationListener<?>> listeners;
Set<String> listenerBeans;
// 获取默认事件监听器
synchronized (this.retrievalMutex) {
// 这些监听器定义在 spring.factories 文件中
listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
}
for (ApplicationListener<?> listener : listeners) {
// 只有对当前 eventType 感兴趣的 listerer 才会添加到监听器列表中
if (supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
retriever.applicationListeners.add(listener);
}
allListeners.add(listener);
}
}
// 通过 bean 名称获取监听器列表
if (!listenerBeans.isEmpty()) {
ConfigurableBeanFactory beanFactory = getBeanFactory();
for (String listenerBeanName : listenerBeans) {
try {
if (supportsEvent(beanFactory, listenerBeanName, eventType)) {
ApplicationListener<?> listener =
beanFactory.getBean(listenerBeanName, ApplicationListener.class);
if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
if (beanFactory.isSingleton(listenerBeanName)) {
retriever.applicationListeners.add(listener);
}
else {
retriever.applicationListenerBeans.add(listenerBeanName);
}
}
allListeners.add(listener);
}
}
else {
Object listener = beanFactory.getSingleton(listenerBeanName);
if (retriever != null) {
retriever.applicationListeners.remove(listener);
}
allListeners.remove(listener);
}
}
catch (NoSuchBeanDefinitionException ex) {
}
}
}
// 对监听器列表进行排序
AnnotationAwareOrderComparator.sort(allListeners);
if (retriever != null && retriever.applicationListenerBeans.isEmpty()) {
retriever.applicationListeners.clear();
retriever.applicationListeners.addAll(allListeners);
}
return allListeners;
}
获取感兴趣的事件判断逻辑
protected boolean supportsEvent(
ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {
// 必须是 GenericApplicationListener 监听器类型,如果不是需要进行转换
GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}
构建为 GenericApplicationListenerAdapter
public GenericApplicationListenerAdapter(ApplicationListener<?> delegate) {
Assert.notNull(delegate, "Delegate listener must not be null");
this.delegate = (ApplicationListener<ApplicationEvent>) delegate;
this.declaredEventType = resolveDeclaredEventType(this.delegate);
}
@Nullable
private static ResolvableType resolveDeclaredEventType(ApplicationListener<ApplicationEvent> listener) {
ResolvableType declaredEventType = resolveDeclaredEventType(listener.getClass());
if (declaredEventType == null || declaredEventType.isAssignableFrom(ApplicationEvent.class)) {
Class<?> targetClass = AopUtils.getTargetClass(listener);
if (targetClass != listener.getClass()) {
declaredEventType = resolveDeclaredEventType(targetClass);
}
}
return declaredEventType;
}
@Nullable
static ResolvableType resolveDeclaredEventType(Class<?> listenerType) {
ResolvableType eventType = eventTypeCache.get(listenerType);
if (eventType == null) {
eventType = ResolvableType.forClass(listenerType).as(ApplicationListener.class).getGeneric();
eventTypeCache.put(listenerType, eventType);
}
return (eventType != ResolvableType.NONE ? eventType : null);
}
进入 GenericApplicationListenerAdapter 类 supportsEventType 和 supportsSourceType 方法
@Override
@SuppressWarnings("unchecked")
public boolean supportsEventType(ResolvableType eventType) {
if (this.delegate instanceof SmartApplicationListener) {
Class<? extends ApplicationEvent> eventClass = (Class<? extends ApplicationEvent>) eventType.resolve();
return (eventClass != null && ((SmartApplicationListener) this.delegate).supportsEventType(eventClass));
}
else {
return (this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType));
}
}
@Override
public boolean supportsSourceType(@Nullable Class<?> sourceType) {
return !(this.delegate instanceof SmartApplicationListener) ||
((SmartApplicationListener) this.delegate).supportsSourceType(sourceType);
}
我们回到 invokeListener 方法的实现上来:
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
}
catch (Throwable err) {
errorHandler.handleError(err);
}
}
else {
doInvokeListener(listener, event);
}
}
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
// 发送事件
listener.onApplicationEvent(event);
} catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
Log logger = LogFactory.getLog(getClass());
if (logger.isTraceEnabled()) {
logger.trace("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}


