Spring事件核心API
前言
Spring事件一般用于应用程序状态变更的通知,也可用于单个服务内特定事件的通知场景。
在Spring中,提供了丰富的api来实现事件机制,一起看下其中包括的核心API。
核心API
事件(ApplicationEvent):Spring事件的抽象基类,用于派生自定义事件,标识着某一类事件。
事件源(EventSource):事件发生的源头,事件初始化时传递给事件的对象。
事件监听器(ApplicationListener):订阅特定的事件,当事件产生时,监听该事件的监听器被触发通知。
事件发布器(ApplicationEventPublisher):定义了发布事件的方法,实现类中,在适当时机发布特定事件。
事件广播器(SimpleApplicationEventMulticaster):用于管理事件监听器和事件的广播,将事件传递给订阅该事件的监听器,作为事件发布器的代理。
事件 ApplicationEvent
// 所有自定义事件的基类,继承java事件api EventObject
public abstract class ApplicationEvent extends EventObject {
/** use serialVersionUID from Spring 1.2 for interoperability. */
private static final long serialVersionUID = 7099057708183571937L;
/** System time when the event happened. */
// 事件发生的系统时间
private final long timestamp;
/**
* Create a new {@code ApplicationEvent}.
* @param source the object on which the event initially occurred or with
* which the event is associated (never {@code null})
* source 不能为null
*/
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
/**
* Return the system time in milliseconds when the event occurred.
*/
public final long getTimestamp() {
return this.timestamp;
}
}
事件源 EventSource
在事件类ApplicationEvent中,构造器传递的source,便是事件源,会传递给EventObject的source成员变量。
事件监听器 ApplicationListener
// 范型要求继承于ApplicationEvent:<E extends ApplicationEvent>
// 继承java事件监听器api EventObject
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
/**
* Handle an application event.
* @param event the event to respond to
*/
void onApplicationEvent(E event);
}
事件发布器 ApplicationEventPublisher
@FunctionalInterface
public interface ApplicationEventPublisher {
// 默认方法
default void publishEvent(ApplicationEvent event) {
publishEvent((Object) event);
}
// 如果事件不是继承ApplicationEvent,会被包装成PayloadApplicationEvent
void publishEvent(Object event);
事件发布器接口,是个函数式接口,有一个默认方法,调用另一个抽象方法,抽象由子类实现,被AbstractApplicationContext实现,AbstractApplicationContext是应用上下文也是企业级容器的一个抽象类,是spring中一个关键的类。
继续看下发布事件的实现抽象类在做什么?
// org.springframework.context.support.AbstractApplicationContext
/**
* Publish the given event to all listeners.
* <p>Note: Listeners get initialized after the MessageSource, to be able
* to access it within listener implementations. Thus, MessageSource
* implementations cannot publish events.
* @param event the event to publish (may be an {@link ApplicationEvent}
* or a payload object to be turned into a {@link PayloadApplicationEvent})
*
* 注意,此处有个说明:监听器注册是在MessageSource后,所以MessageSource实现中不建议发布事件。
*
* 此处还提到,event可能是一个ApplicationEvent实现类,也可能不是,如果不是,会包装成PayloadApplicationEvent事件
*/
@Override
public void publishEvent(Object event) {
publishEvent(event, null);
}
/**
* Publish the given event to all listeners.
* @param event the event to publish (may be an {@link ApplicationEvent}
* or a payload object to be turned into a {@link PayloadApplicationEvent})
* @param eventType the resolved event type, if known
* @since 4.2
*/
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
// Decorate event as an ApplicationEvent if necessary
// 如果属于ApplicationEvent则强转
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
else {
// 如果发布的不是ApplicationEvent,则包装一个PayloadApplicationEvent
applicationEvent = new PayloadApplicationEvent<>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
}
}
// Multicast right now if possible - or lazily once the multicaster is initialized
// 如果可能的话,立马进行广播事件,否则延迟到multicaster初始化后。
// 因为在 getApplicationEventMulticaster()
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
// 获取广播器发送事件
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
// Publish event via parent context as well...
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}
有个注意事项:
监听器注册是在MessageSource后,所以MessageSource实现中不建议发布事件。但是可以向ApplicationContext中增加监听器,等待事件广播器注册后,会立马进行发布。
其中有个getApplicationEventMulticaster()方法,一起看下:
// org.springframework.context.support.AbstractApplicationContext
ApplicationEventMulticaster getApplicationEventMulticaster() throws IllegalStateException {
if (this.applicationEventMulticaster == null) {
throw new IllegalStateException("ApplicationEventMulticaster not initialized - " +
"call 'refresh' before multicasting events via the context: " + this);
}
return this.applicationEventMulticaster;
}
获取广播器,固定bean名称:APPLICATION_EVENT_MULTICASTER_BEAN_NAME = “applicationEventMulticaster”。
在AbstractApplicationContext#initApplicationEventMulticaster中被初始化。
所以事件的发布时通过事件广播器 ApplicationEventMulticaster进行发布的,继续看下事件广播器ApplicationEventMulticaster。
事件广播器
包括3个如下api:
ApplicationEventMulticaster:是个接口,用于管理事件监听器,同时负责将事件广播给监听了该事件的监听器。
AbstractApplicationEventMulticaster:抽象类,实现ApplicationEventMulticaster接口,提供了大部分核心逻辑。
SimpleApplicationEventMulticaster:唯一实现类,继承AbstractApplicationEventMulticaster类,同时支持Executor异步回调监听器(默认同步调用)与错误处理ErrorHandler(默认监听器异常进行抛出),api相对简单。
下面主要看下核心api AbstractApplicationEventMulticaster类的定义说明
// ApplicationEventMulticaster接口的抽象实现
public abstract class AbstractApplicationEventMulticaster
implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {
// 默认监听器的回收器,包括所有的。
// 以此为锁,保障defaultRetriever中数据操作的线程安全
// Helper class that encapsulates(封装) a general set of target listeners.
private final DefaultListenerRetriever defaultRetriever = new DefaultListenerRetriever();
// 监听器缓存,key:事件类型和事件源Class;value:目标监听器集合
// 在根据事件类型获取监听器时使用
// Helper class that encapsulates a specific set of target listeners
final Map<ListenerCacheKey, CachedListenerRetriever> retrieverCache = new ConcurrentHashMap<>(64);
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
synchronized (this.defaultRetriever) {
// Explicitly remove target for a proxy, if registered already,
// in order to avoid double invocations of the same listener.
// 去除代理的事件监听器,防止重复回调。这里代理类,是单例类在aop的场景下经过SingletonTargetSource包装的类
Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
if (singletonTarget instanceof ApplicationListener) {
this.defaultRetriever.applicationListeners.remove(singletonTarget);
}
this.defaultRetriever.applicationListeners.add(listener);
this.retrieverCache.clear();
}
}
// ... 省略了些添加和移除监听器的实现方法,及获取全量监听器的方法
/**
* 获取指定事件类型的监听器集合
*
* @param eventType the event type
* @return a Collection of ApplicationListeners
*/
protected Collection<ApplicationListener<?>> getApplicationListeners(
ApplicationEvent event, ResolvableType eventType) {
// 事件源
Object source = event.getSource();
// 事件源类Class对象
Class<?> sourceType = (source != null ? source.getClass() : null);
// 监听器缓存key,按事件类型和事件源类型
ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
// Potential new retriever to populate
CachedListenerRetriever newRetriever = null;
// 从缓存中去
CachedListenerRetriever existingRetriever = this.retrieverCache.get(cacheKey);
if (existingRetriever == null) {
// Caching a new ListenerRetriever if possible
if (this.beanClassLoader == null ||
(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
newRetriever = new CachedListenerRetriever();
existingRetriever = this.retrieverCache.putIfAbsent(cacheKey, newRetriever);
if (existingRetriever != null) {
newRetriever = null; // no need to populate it in retrieveApplicationListeners
}
}
}
// 缓存中有,返回特定事件和事件源类型的监听器集合
if (existingRetriever != null) {
Collection<ApplicationListener<?>> result = existingRetriever.getApplicationListeners();
if (result != null) {
return result;
}
}
// 匹配事件监听器
return retrieveApplicationListeners(eventType, sourceType, newRetriever);
}
/**
* 解析对应事件和源类型的监听器,记录事件与监听器的对应关系并存入缓存中
* 支持事件监听器类和监听器bean名称查询
*
* @return the pre-filtered list of application listeners for the given event and source type
*/
private Collection<ApplicationListener<?>> retrieveApplicationListeners(
ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable CachedListenerRetriever retriever) {
List<ApplicationListener<?>> allListeners = new ArrayList<>();
// retriever不为null时,才会处理filteredListeners和filteredListenerBeans字段。处理完赋值进去。
Set<ApplicationListener<?>> filteredListeners = (retriever != null ? new LinkedHashSet<>() : null);
// 存在bean名称,且不是单例
Set<String> filteredListenerBeans = (retriever != null ? new LinkedHashSet<>() : null);
Set<ApplicationListener<?>> listeners;
Set<String> listenerBeans;
synchronized (this.defaultRetriever) {
listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
}
// Add programmatically registered listeners, including ones coming
// from ApplicationListenerDetector (singleton beans and inner beans).
for (ApplicationListener<?> listener : listeners) {
if (supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
filteredListeners.add(listener);
}
allListeners.add(listener);
}
}
// Add listeners by bean name
if (!listenerBeans.isEmpty()) {
ConfigurableBeanFactory beanFactory = getBeanFactory();
for (String listenerBeanName : listenerBeans) {
try {
// beanFactory检查bean定义的监听器的泛型声明,是不是对应事件类型。
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)) {
filteredListeners.add(listener);
}
else {
filteredListenerBeans.add(listenerBeanName);
}
}
allListeners.add(listener);
}
}
else {
Object listener = beanFactory.getSingleton(listenerBeanName);
if (retriever != null) {
filteredListeners.remove(listener);
}
// 移除掉不匹配的
allListeners.remove(listener);
}
}
catch (NoSuchBeanDefinitionException ex) {
// Singleton listener instance (without backing bean definition) disappeared -
// probably in the middle of the destruction phase
}
}
}
AnnotationAwareOrderComparator.sort(allListeners);
if (retriever != null) {
if (filteredListenerBeans.isEmpty()) {
// 没有该情况:存在bean名称且不是单例的beanName,使用allListeners即可
// 如果存在bean名称的数据且是单例,会直接存储对应bean,上层调用时不用再转了。
retriever.applicationListeners = new LinkedHashSet<>(allListeners);
retriever.applicationListenerBeans = filteredListenerBeans;
}
else {
// 否则使用过滤的filteredListeners bean
retriever.applicationListeners = filteredListeners;
retriever.applicationListenerBeans = filteredListenerBeans;
}
}
return allListeners;
}
/**
* 检查bean定义的监听器的泛型声明,是不是对应事件类型。
*
* 还有其他的supportsEvent方法,主要用来判断监听器是否对应该事件。
*
* @return whether the given listener should be included in the candidates
* for the given event type
*/
private boolean supportsEvent(
ConfigurableBeanFactory beanFactory, String listenerBeanName, ResolvableType eventType) {
Class<?> listenerType = beanFactory.getType(listenerBeanName);
if (listenerType == null || GenericApplicationListener.class.isAssignableFrom(listenerType) ||
SmartApplicationListener.class.isAssignableFrom(listenerType)) {
return true;
}
if (!supportsEvent(listenerType, eventType)) {
return false;
}
try {
BeanDefinition bd = beanFactory.getMergedBeanDefinition(listenerBeanName);
ResolvableType genericEventType = bd.getResolvableType().as(ApplicationListener.class).getGeneric();
return (genericEventType == ResolvableType.NONE || genericEventType.isAssignableFrom(eventType));
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore - no need to check resolvable type for manually registered singleton
return true;
}
}
api中多个方法增加了synchronized同步锁:
一方面,因为涉及两个缓冲,定义为共享变量,需要保证操作的原子性;另一方面,监听器缓存中存储的是线程不安全的集合类型,在操作时需要保证线程的安全。故而要增加synchronized同步锁机制。
还有个判断方法:
protected boolean supportsEvent(Class<?> listenerType, ResolvableType eventType) {
ResolvableType declaredEventType = GenericApplicationListenerAdapter.resolveDeclaredEventType(listenerType);
return (declaredEventType == null || declaredEventType.isAssignableFrom(eventType));
}
通过isAssignableFrom可知,只要监听器声明的事件是发布事件的父类,监听器都能收到,例如监听器监听ApplicationEvent,那么发布任何ApplicationEvent的子类,监听器均能收到消息。
总结
了解整个Spring事件的设计,包括一些实现的细节。能够注意到,对于监听器声明的事件,如果其声明事件是发布事件的父类,事件监听器便可以收到通知。
同时可以借鉴,Spring事件场景,一般事件的监听器定义在服务启动后比较固定,而发布事件可能随时发生,对于获取监听器来说,可以理解为读多写少的场景,考虑增加缓存,来提高执行效率。