spring–基于XML
的事件监听原理
文章目录
1 概念
观察者模式的典型代表就是监听器,那么spring
是如何使用它的呢?
2 spring
提供的标准事件
事件 | 说明 |
---|---|
ContextRefreshedEvent | 在ApplicationContext 初始化或刷新完成时发布(finishRefresh() 中发布该事件) |
ContextStartedEvent | ApplicationContext 调用生命周期接口的start() 方法发布该事件。通常,此start() 方法用于在显式停止后重新启动组件,但也可以用于启动尚未配置为自动启动的组件(例如,尚未在初始化时启动的组件)。 |
ContextStoppedEvent | ApplicationContext 调用生命周期接口的stop() 方法发布该事件。此处,“Stopped” 表示所有Lifecycle bean 均收到明确的停止信号。停止的上下文可以通过start() 方法调用重新启动 。 |
ContextClosedEvent | ApplicationContext 调用生命周期接口的close() 方法发布该事件,在这里,“Closed” 意味着所有单例bean 都将被销毁。关闭上下文后,它将达到使用寿命,无法刷新或重新启动 |
RequestHandledEvent | 一个特定于Web 的事件,告诉所有Bean ,HTTP 请求已得到服务。请求完成后,将发布此事件。此事件仅适用于使用Spring 的Web 应用程序DispatcherServlet 。 |
ServletRequestHandledEvent | RequestHandledEvent 类的子类,添加了特定于Servlet 的上下文信息。 |
2.1 自定义事件
我们可以创建和发布自己的自定义事件,只需要实现ApplicationEvent
接口即可。
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})
*/
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;
}
}
ApplicationEvent
中定义了一个时间戳,记录当前事件的产生时间- 只有一个默认的有参构造方法,创建事件的时候,必须把事件要操作的对象设置进去
下面是我们自定义的BlockedListEvent
事件
public class BlockedListEvent extends ApplicationEvent {
//事件携带的信息
private final String address;
private final String content;
public BlockedListEvent(Object source, String address, String content) {
super(source);
this.address = address;
this.content = content;
}
// accessor and other methods...
}
2.2 发布事件
要想发布一个事件,我们就必须得到事件多播器,
spring
提供了一个接口ApplicationEventPublisherAware
,用户只需要实现这个接口,spring
就会在创建对象的时候自动调用接口的setApplicationEventPublisher
方法,将应用事件发布器
注入进去。
public class EmailService implements ApplicationEventPublisherAware {
private List<String> blockedList;
private ApplicationEventPublisher publisher;
public void setBlockedList(List<String> blockedList) {
this.blockedList = blockedList;
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
public void sendEmail(String address, String content) {
if (blockedList.contains(address)) {
/**
* BlockedListEvent是用户自定义的事件,只需要实现ApplicationEvent接口即可
* 调用publishEvent方法发布一个BlockedListEvent事件
*/
publisher.publishEvent(new BlockedListEvent(this, address, content));
return;
}
// send email...
}
}
3 事件多播器ApplicationEventMulticaster
3.1 spring
启动过程中自动创建事件多播器
/**
* Initialize the ApplicationEventMulticaster.
* Uses SimpleApplicationEventMulticaster if none defined in the context.
* @see org.springframework.context.event.SimpleApplicationEventMulticaster
*/
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
/**
* 用户可以自定义一个名字为applicationEventMulticaster的事件多播器,
* 在容器启动过程中,会为上下文自动实例化这个多播器
* 5.2中发布事件的时候会使用上下文的这个事件多播器发布事件
*/
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
//使用容器默认的事件多播器
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}
3.2 默认的事件多播器SimpleApplicationEventMulticaster
下面是它的UML
图
从图上可以看到,它实现了两个Aware
接口,也就是说它在被spring
创建的时候可以自动向对象中注入BeanFactory
对象和ClassLoader
对象。那接下来我们再看看ApplicationEventMulticaster
接口有哪些方法,它能做什么?
总结:
addApplicationListener
方法和addApplicationListenerBean
方法:向多播器中注册监听器removeApplicationListener
方法、removeApplicationListenerBean
方法和removeAllListeners
方法:移除监听器multicastEvent
方法:发布事件
3.3 AbstractApplicationEventMulticaster
的几个内部类的作用
spring
事件多播器实现并不简单,因为多播器内部就已经进行了事件和监听器的匹配。只要用户监听器实现
ApplicationListener
接口的时候指定泛型,也就是监听事件的类型,spring
就会自动将该事件推送给泛型匹配的监听器,而不会推送给别的监听器。
下面是该类的两个重要属性:
//所有的监听器都保存在这里面
private final DefaultListenerRetriever defaultRetriever = new DefaultListenerRetriever();
/**
* 缓存
* key为封装的事件类型
* value为能够监听该事件类型的所有监听器
*/
final Map<ListenerCacheKey, CachedListenerRetriever> retrieverCache = new ConcurrentHashMap<>(64);
下面我们就来看一下它所涉及到的三个内部类
3.3.1 ListenerCacheKey
(封装的事件类型)
/**
* Cache key for ListenerRetrievers, based on event type and source type.
*/
private static final class ListenerCacheKey implements Comparable<ListenerCacheKey> {
//事件的ResolvableType类型
private final ResolvableType eventType;
//事件源对象的类型,见6.3
@Nullable
private final Class<?> sourceType;
public ListenerCacheKey(ResolvableType eventType, @Nullable Class<?> sourceType) {
Assert.notNull(eventType, "Event type must not be null");
this.eventType = eventType;
this.sourceType = sourceType;
}
@Override
public boolean equals(@Nullable Object other) {
if (this == other) {
return true;
}
if (!(other instanceof ListenerCacheKey)) {
return false;
}
ListenerCacheKey otherKey = (ListenerCacheKey) other;
return (this.eventType.equals(otherKey.eventType) &&
ObjectUtils.nullSafeEquals(this.sourceType, otherKey.sourceType));
}
@Override
public int hashCode() {
return this.eventType.hashCode() * 29 + ObjectUtils.nullSafeHashCode(this.sourceType);
}
@Override
public String toString() {
return "ListenerCacheKey [eventType = " + this.eventType + ", sourceType = " + this.sourceType + "]";
}
//排序策略
@Override
public int compareTo(ListenerCacheKey other) {
int result = this.eventType.toString().compareTo(other.eventType.toString());
if (result == 0) {
if (this.sourceType == null) {
return (other.sourceType == null ? 0 : -1);
}
if (other.sourceType == null) {
return 1;
}
result = this.sourceType.getName().compareTo(other.sourceType.getName());
}
return result;
}
}
总结:
- 实现了
Comparable
接口,那么就能对retrieverCache
这个Map
集合进行排序了- 该类封装了事件源对象的类型和事件类型,也就是说
spring
是根据这两种类型来确定监听器
3.3.2 CachedListenerRetriever
(事件多播器缓存某种事件对应的监听器的地方)
/**
* Helper class that encapsulates a specific set of target listeners,
* allowing for efficient retrieval of pre-filtered listeners.
* <p>An instance of this helper gets cached per event type and source type.
*/
private class CachedListenerRetriever {
@Nullable
public volatile Set<ApplicationListener<?>> applicationListeners;
@Nullable
public volatile Set<String> applicationListenerBeans;
@Nullable
public Collection<ApplicationListener<?>> getApplicationListeners() {
Set<ApplicationListener<?>> applicationListeners = this.applicationListeners;
Set<String> applicationListenerBeans = this.applicationListenerBeans;
if (applicationListeners == null || applicationListenerBeans == null) {
// Not fully populated yet
return null;
}
List<ApplicationListener<?>> allListeners = new ArrayList<>(
applicationListeners.size() + applicationListenerBeans.size());
allListeners.addAll(applicationListeners);
if (!applicationListenerBeans.isEmpty()) {
BeanFactory beanFactory = getBeanFactory();
for (String listenerBeanName : applicationListenerBeans) {
try {
allListeners.add(beanFactory.getBean(listenerBeanName, ApplicationListener.class));
}
catch (NoSuchBeanDefinitionException ex) {
// Singleton listener instance (without backing bean definition) disappeared -
// probably in the middle of the destruction phase
}
}
}
//排序
if (!applicationListenerBeans.isEmpty()) {
AnnotationAwareOrderComparator.sort(allListeners);
}
return allListeners;
}
}
CachedListenerRetriever
和DefaultListenerRetriever
两个类的结构基本一模一样,但是他们的左右不一样,从名字就可以看出来。
CachedListenerRetriever
:它存储了监听某种事件的所有监听器,这样发布事件的时候,就没有必要每次从所有的监听器中找
3.3.3 DefaultListenerRetriever
(事件多播器存储所有监听器的地方)
/**
* Helper class that encapsulates a general set of target listeners.
*/
private class DefaultListenerRetriever {
public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();
public final Set<String> applicationListenerBeans = new LinkedHashSet<>();
public Collection<ApplicationListener<?>> getApplicationListeners() {
List<ApplicationListener<?>> allListeners = new ArrayList<>(
this.applicationListeners.size() + this.applicationListenerBeans.size());
allListeners.addAll(this.applicationListeners);
//getBean方法获取applicationListenerBeans集合名字对应的监听器对象
if (!this.applicationListenerBeans.isEmpty()) {
BeanFactory beanFactory = getBeanFactory();
for (String listenerBeanName : this.applicationListenerBeans) {
try {
ApplicationListener<?> listener =
beanFactory.getBean(listenerBeanName, ApplicationListener.class);
if (!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
}
}
}
//排序
AnnotationAwareOrderComparator.sort(allListeners);
return allListeners;
}
}
总结:
applicationListeners
集合保存事件多播器中所有的监听器对象applicationListenerBeans
集合保存事件多播器中所有的监听器的beanName
- 唯一的方法
getApplicationListeners()
会获取到事件多播器中所有的监听器对象,会使用getBean
方法得到applicationListenerBeans
集合保存的beanName
对应的监听器对象。
4 监听器监听事件
为了能够收到发布的事件,我们必须提供监听器监听事件
4.1 spring
自动识别监听器
首先,容器启动过程中会自动容器中的监听器,无论监听器是否被实例化
/**
* Add beans that implement ApplicationListener as listeners.
* Doesn't affect other listeners, which can be added without being beans.
*/
protected void registerListeners() {
// Register statically specified listeners first.
//将已经实例化的listener注册到多播器中
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let post-processors apply to them!
//获取容器中所有BeanDefinition中的监听器的名字,并注册名字到多播器中,这里没有实例化这些监听器
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// Publish early application events now that we finally have a multicaster...
//使用多播器发布所有早期事件
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
//使容器中的早期事件集合失效,因为此时已经有事件多播器了,事件可以直接发布,不需要缓存
this.earlyApplicationEvents = null;
if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
其次,spring
还提供了一个ApplicationListenerDetector
,它实现了MergedBeanDefinitionPostProcessor
接口,ApplicationListenerDetector
主要是用来检测这个bean
是否实现了ApplicationListener
接口,实际就是判断这个bean
是不是一个监听器,如果是监听器,就注册到事件多播器中。
下面是这个BeanPostProcessor
的两个比较重要的方法
//缓存实例化的监听器名
private final transient Map<String, Boolean> singletonNames = new ConcurrentHashMap<>(256);
//bean实例化后执行
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
//监听器
if (ApplicationListener.class.isAssignableFrom(beanType)) {
/**
* 保存到当前对象singletonNames属性中
* map集合的value值代表这个监听器是不是单例的
*/
this.singletonNames.put(beanName, beanDefinition.isSingleton());
}
}
//bean初始化完成后执行
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof ApplicationListener) {
// potentially not detected as a listener by getBeanNamesForType retrieval
Boolean flag = this.singletonNames.get(beanName);
//单例的监听器
if (Boolean.TRUE.equals(flag)) {
// singleton bean (top-level or inner): register on the fly
//将监听器添加到应用上下文和事件多播器中
this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
}
//保存非单例的监听器主要是为了输出日志
else if (Boolean.FALSE.equals(flag)) {
if (logger.isWarnEnabled() && !this.applicationContext.containsBean(beanName)) {
// inner bean with other scope - can't reliably process events
logger.warn("Inner bean '" + beanName + "' implements ApplicationListener interface " +
"but is not reachable for event multicasting by its containing ApplicationContext " +
"because it does not have singleton scope. Only top-level listener beans are allowed " +
"to be of non-singleton scope.");
}
//去掉非单例的监听器缓存
this.singletonNames.remove(beanName);
}
}
return bean;
}
将监听器添加到应用上下文和事件多播器中
/** Statically specified listeners. */
//上下文中用来保存监听器对象的集合
private final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
Assert.notNull(listener, "ApplicationListener must not be null");
//有事件多播器就把监听器注册进去,事件多播器创建在3.8章节
if (this.applicationEventMulticaster != null) {
this.applicationEventMulticaster.addApplicationListener(listener);
}
//保存在上下文中
this.applicationListeners.add(listener);
}
4.2 自定义监听器监听自定义事件
@Component
public class BlockedListNotifier implements ApplicationListener<BlockedListEvent> {
private String notificationAddress;
public void setNotificationAddress(String notificationAddress) {
this.notificationAddress = notificationAddress;
}
@Override
public void onApplicationEvent(BlockedListEvent event) {
// notify appropriate parties via notificationAddress...
}
}
- 监听器必须交由
spring
管理,才会生效- 必须实现
ApplicationListener
接口(注解方式另外说)- 通过泛型约束来指定该监听器监听的事件类型
5 使用应用事件发布器ApplicationEventPublisher
发布事件
先来看一下ApplicationEventPublisher
接口
public interface ApplicationEventPublisher {
//发布ApplicationEvent事件
default void publishEvent(ApplicationEvent event) {
publishEvent((Object) event);
}
//发布任意事件
void publishEvent(Object event);
}
这个接口定义了两个方法,一个有类型约束,一个没有,
spring
推荐使用有类型约束的那个发布事件方法
接下来我们看看publishEvent
方法是如何发布事件的。
5.1 注入ApplicationEventPublisher
(应用事件发布器)
现在有一个疑问,通过ApplicationEventPublisherAware
接口注入进去的是不是容器中的事件多播器ApplicationEventMulticaster
呢?很明显不是,它们两个的类型就不一样。那么这个ApplicationEventPublisher
对象到底是什么呢?
我们知道通过ApplicationContextAwareProcessor
这个BeanPostProcessor
可以完成Environment
、EmbeddedValueResolver
、ResourceLoader
、ApplicationEventPublisher
、MessageSource
、ApplicationContext
这6
个对象注入,下面是注入过程:
/**
* bean对象初始化之前调用
*/
@Override
@Nullable
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//未实现这些aware接口就什么也不做
if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
return bean;
}
AccessControlContext acc = null;
if (System.getSecurityManager() != null) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}
if (acc != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareInterfaces(bean);
return null;
}, acc);
}
else {
//执行Aware接口方法
invokeAwareInterfaces(bean);
}
return bean;
}
/**
* 调用这些aware接口set方法
*/
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
//原来这个ApplicationEventPublisher就是应用上下文对象啊
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
注入的是应用上下文对象
5.2 publishEvent
方法发布事件原理
ApplicationEventPublisher
接口的方法最终在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 application-specific or a
* standard framework event)
*/
@Override
public void publishEvent(ApplicationEvent event) {
publishEvent(event, null);
}
/**
* 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})
*/
@Override
public void publishEvent(Object event) {
publishEvent(event, null);
}
两个方法最终都是调用publishEvent(Object event, @Nullable ResolvableType eventType)
来完成事件发布
/**
* 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;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
//非ApplicationEvent事件
else {
//将事件包装为PayloadApplicationEvent
applicationEvent = new PayloadApplicationEvent<>(this, event);
//使用ResolvableType解析event事件的类型和适配器PayloadApplicationEvent的泛型约束信息
if (eventType == null) {
eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
}
}
// Multicast right now if possible - or lazily once the multicaster is initialized
//说明此时容器中还未创建事件多播器ApplicationEventMulticaster
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);
}
}
}
获取上下文的事件多播器
/**
* Return the internal ApplicationEventMulticaster used by the context.
* @return the internal ApplicationEventMulticaster (never {@code null})
* @throws IllegalStateException if the context has not been initialized yet
*/
ApplicationEventMulticaster getApplicationEventMulticaster() throws IllegalStateException {
if (this.applicationEventMulticaster == null) {
throw new IllegalStateException("ApplicationEventMulticaster not initialized - " +
"call 'refresh' before multicasting events via the context: " + this);
}
//使用上下文的事件多播器,见3.1
return this.applicationEventMulticaster;
}
从上面我们可以发现,真正执行事件发布是事件多播器
ApplicationEventMulticaster
6 spring
默认的事件多播器SimpleApplicationEventMulticaster
发布事件
multicastEvent
方法发布事件
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
//6.1解析获取事件ResolvableType类型
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
//6.2获取异步执行器并执行异步任务
Executor executor = getTaskExecutor();
//6.3获取监听对应事件的所有监听器
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
//6.4执行监听器
invokeListener(listener, event);
}
}
}
6.1 解析获取事件ResolvableType
类型
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
6.1.1 没有实现ApplicationEvent
接口的事件
对于没有实现
ApplicationEvent
接口的事件,使用ApplicationEventPublisher
发布事件的时候,自动适配为PayloadApplicationEvent
类型,并且解析事件真实类型和适配器PayloadApplicationEvent
的泛型约束信息。见5.2
//将事件包装为PayloadApplicationEvent
applicationEvent = new PayloadApplicationEvent<>(this, event);
//使用ResolvableType解析event事件的类型和适配器PayloadApplicationEvent的泛型约束信息
if (eventType == null) {
eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
}
PayloadApplicationEvent
类非常简单,你可以把它理解为适配器,将非ApplicationEvent
类型事件适配为ApplicationEvent
类型,下面是该类的源码:
public class PayloadApplicationEvent<T> extends ApplicationEvent implements ResolvableTypeProvider {
//原事件对象
private final T payload;
/**
* Create a new PayloadApplicationEvent.
* @param source the object on which the event initially occurred (never {@code null})
* @param payload the payload object (never {@code null})
*/
public PayloadApplicationEvent(Object source, T payload) {
//保存事件产生位置的类的对象
super(source);
Assert.notNull(payload, "Payload must not be null");
this.payload = payload;
}
//使用ResolvableType解析event事件的类型和泛型约束信息
@Override
public ResolvableType getResolvableType() {
/**
* getClass()是获取当前类PayloadApplicationEvent的clazz对象
* 也就是说不是解析原事件对象的泛型信息
*/
return ResolvableType.forClassWithGenerics(getClass(), ResolvableType.forInstance(getPayload()));
}
//返回原事件对象
public T getPayload() {
return this.payload;
}
}
6.1.2 实现了ApplicationEvent
接口的事件
实现了
ApplicationEvent
接口的事件,则会在此时调用resolveDefaultEventType
方法解析事件真实类型。
private ResolvableType resolveDefaultEventType(ApplicationEvent event) {
return ResolvableType.forInstance(event);
}
最终都是使用ResolvableType.forInstance(event)
方法解析事件真实类型。
6.2 获取异步执行器并执行异步任务
//用户可以指定一个异步执行器,事件多播器会自动使用它来执行任务
@Nullable
private Executor taskExecutor;
/**
* Return the current task executor for this multicaster.
*/
@Nullable
protected Executor getTaskExecutor() {
return this.taskExecutor;
}
我们可以自定义一个事件多播器,并指定它的异步执行器
<bean id="applicationEventMulticaster" class="org.springframework.context.event.SimpleApplicationEventMulticaster">
<property name="taskExecutor" ref="taskExecutor"></property>
</bean>
<!--静态工厂方法创建只有一个线程的线程池-->
<bean id="taskExecutor" class="java.util.concurrent.Executors" factory-method="newSingleThreadExecutor"></bean>
6.3获取监听对应事件的所有监听器
/**
* Return a Collection of ApplicationListeners matching the given
* event type. Non-matching listeners get excluded early.
* @param event the event to be propagated. Allows for excluding
* non-matching listeners early, based on cached matching information.
* @param eventType the event type
* @return a Collection of ApplicationListeners
* @see org.springframework.context.ApplicationListener
*/
protected Collection<ApplicationListener<?>> getApplicationListeners(
ApplicationEvent event, ResolvableType eventType) {
//获取事件源对象
Object source = event.getSource();
//事件源对象的clazz对象
Class<?> sourceType = (source != null ? source.getClass() : null);
//从这里就知道spring是根据事件源对象的类型和事件类型来确定监听器的
ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
// Potential new retriever to populate
CachedListenerRetriever newRetriever = null;
// Quick check for existing entry on ConcurrentHashMap
//先获取缓存
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;
}
// If result is null, the existing retriever is not fully populated yet by another thread.
// Proceed like caching wasn't possible for this current local attempt.
}
//缓存中没有监听器,就匹配事件多播器中保存的所有监听器,找到能收到该事件的监听器,见6.3.1
return retrieveApplicationListeners(eventType, sourceType, newRetriever);
}
6.3.1 匹配事件多播器中保存的所有监听器,找到能收到该事件的监听器
/**
* Actually retrieve the application listeners for the given event and source type.
* @param eventType the event type
* @param sourceType the event source type
* @param retriever the ListenerRetriever, if supposed to populate one (for caching purposes)
* @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<>();
Set<ApplicationListener<?>> filteredListeners = (retriever != null ? new LinkedHashSet<>() : null);
Set<String> filteredListenerBeans = (retriever != null ? new LinkedHashSet<>() : null);
Set<ApplicationListener<?>> listeners;
Set<String> listenerBeans;
synchronized (this.defaultRetriever) {
//监听器对象
listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
//监听器的beanName
listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
}
// Add programmatically registered listeners, including ones coming
// from ApplicationListenerDetector (singleton beans and inner beans).
//遍历监听器对象,找到可以接收该事件的监听器
for (ApplicationListener<?> listener : listeners) {
//判断listener是否支持该事件类型和事件源对象类型,见6.3.2
if (supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
filteredListeners.add(listener);
}
allListeners.add(listener);
}
}
// Add listeners by bean name, potentially overlapping with programmatically
// registered listeners above - but here potentially with additional metadata.
if (!listenerBeans.isEmpty()) {
ConfigurableBeanFactory beanFactory = getBeanFactory();
//遍历监听器beanName,找到可以接收该事件的监听器
for (String listenerBeanName : listenerBeans) {
try {
//早期过滤listenerBeanName对应的监听器,见6.3.4
if (supportsEvent(beanFactory, listenerBeanName, eventType)) {
//实例化
ApplicationListener<?> listener =
beanFactory.getBean(listenerBeanName, ApplicationListener.class);
//再次判断,见6.3.2
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 {
// Remove non-matching listeners that originally came from
// ApplicationListenerDetector, possibly ruled out by additional
// BeanDefinition metadata (e.g. factory method generics) above.
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()) {
retriever.applicationListeners = new LinkedHashSet<>(allListeners);
retriever.applicationListenerBeans = filteredListenerBeans;
}
else {
retriever.applicationListeners = filteredListeners;
retriever.applicationListenerBeans = filteredListenerBeans;
}
}
return allListeners;
}
6.3.2 判断监听器是否支持该事件类型和事件源对象类型
/**
* Determine whether the given listener supports the given event.
* <p>The default implementation detects the {@link SmartApplicationListener}
* and {@link GenericApplicationListener} interfaces. In case of a standard
* {@link ApplicationListener}, a {@link GenericApplicationListenerAdapter}
* will be used to introspect the generically declared type of the target listener.
* @param listener the target listener to check
* @param eventType the event type to check against
* @param sourceType the source type to check against
* @return whether the given listener should be included in the candidates
* for the given event type
*/
protected boolean supportsEvent(
ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {
//将所有监听器统一适配为GenericApplicationListener
GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
//使用GenericApplicationListener类中定义的方法,同时检查监听器是否支持该事件类型和事件源对象类型
return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}
6.3.3 GenericApplicationListener
和GenericApplicationListenerAdapter
GenericApplicationListener
是ApplicationListener
的子接口,该接口额外添加了3
个方法,supportsEventType()
方法判断该监听器能否处理eventType
类型的事件,supportsSourceType()
方法判断该监听器能否处理事件源对象类型为sourceType
的事件,并且只有这两个方法判断均为true
才能断定该监听器能够处理该事件。getOrder()
方法指定监听器的优先级
public interface GenericApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered {
boolean supportsEventType(ResolvableType eventType);
default boolean supportsSourceType(@Nullable Class<?> sourceType) {
return true;
}
@Override
default int getOrder() {
return LOWEST_PRECEDENCE;
}
}
GenericApplicationListenerAdapter
如其名,它是一个监听器适配器,能够将非GenericApplicationListener
类型的监听器适配为GenericApplicationListener
类型。
public class GenericApplicationListenerAdapter implements GenericApplicationListener, SmartApplicationListener {
private static final Map<Class<?>, ResolvableType> eventTypeCache = new ConcurrentReferenceHashMap<>();
//原始的监听器对象
private final ApplicationListener<ApplicationEvent> delegate;
//事件类型
@Nullable
private final ResolvableType declaredEventType;
/**
* Create a new GenericApplicationListener for the given delegate.
* @param delegate the delegate listener to be invoked
*/
@SuppressWarnings("unchecked")
public GenericApplicationListenerAdapter(ApplicationListener<?> delegate) {
Assert.notNull(delegate, "Delegate listener must not be null");
this.delegate = (ApplicationListener<ApplicationEvent>) delegate;
//构造对象时就解析监听器能够监听的事件类型
this.declaredEventType = resolveDeclaredEventType(this.delegate);
}
//监听器接收事件的方法
@Override
public void onApplicationEvent(ApplicationEvent event) {
//调用原始的监听器对象的onApplicationEvent方法
this.delegate.onApplicationEvent(event);
}
//监听器是否支持该事件类型
@Override
@SuppressWarnings("unchecked")
public boolean supportsEventType(ResolvableType eventType) {
//SmartApplicationListener的支持的事件类型判断
if (this.delegate instanceof SmartApplicationListener) {
Class<? extends ApplicationEvent> eventClass = (Class<? extends ApplicationEvent>) eventType.resolve();
return (eventClass != null && ((SmartApplicationListener) this.delegate).supportsEventType(eventClass));
}
/**
* 1.监听器未指定泛型,那么经过resolveDeclaredEventType方法解析结果就为null,表明
* 监听所有类型事件
* 2.监听器指定的泛型类型为事件类型的父类或相同
* 这两种情况都表明该监听器可以接收该种类型的事件
*/
else {
return (this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType));
}
}
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return supportsEventType(ResolvableType.forClass(eventType));
}
//监听器是否支持该事件源对象类型
@Override
public boolean supportsSourceType(@Nullable Class<?> sourceType) {
/**
* 只要我们的监听器不是SmartApplicationListener类型,该方法的返回值总是为true
* 并且后面的逻辑判断直接忽略
* 如果要使我们的监听器只能处理特定的事件源对象类型的事件,那我们的监听器只需要实现
* SmartApplicationListener接口,然后重写supportsSourceType()方法,自定义判断逻辑即可
*/
return !(this.delegate instanceof SmartApplicationListener) ||
((SmartApplicationListener) this.delegate).supportsSourceType(sourceType);
}
@Override
public int getOrder() {
return (this.delegate instanceof Ordered ? ((Ordered) this.delegate).getOrder() : Ordered.LOWEST_PRECEDENCE);
}
@Nullable
private static ResolvableType resolveDeclaredEventType(ApplicationListener<ApplicationEvent> listener) {
//获取监听器ApplicationListener接口上的泛型信息
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) {
//获取监听器ApplicationListener接口上的泛型信息
eventType = ResolvableType.forClass(listenerType).as(ApplicationListener.class).getGeneric();
//解析的结果放入缓存中
eventTypeCache.put(listenerType, eventType);
}
return (eventType != ResolvableType.NONE ? eventType : null);
}
}
该类判断非GenericApplicationListener
类型的监听器是否支持该事件类型和事件源对象类型
6.3.4 早期过滤listenerBeanName
对应的监听器(初步判断是否支持该事件类型)
/**
* Filter a bean-defined listener early through checking its generically declared
* event type before trying to instantiate it.
* <p>If this method returns {@code true} for a given listener as a first pass,
* the listener instance will get retrieved and fully evaluated through a
* {@link #supportsEvent(ApplicationListener, ResolvableType, Class)} call afterwards.
* @param beanFactory the BeanFactory that contains the listener beans
* @param listenerBeanName the name of the bean in the BeanFactory
* @param eventType the event type to check
* @return whether the given listener should be included in the candidates
* for the given event type
* @see #supportsEvent(Class, ResolvableType)
* @see #supportsEvent(ApplicationListener, ResolvableType, Class)
*/
private boolean supportsEvent(
ConfigurableBeanFactory beanFactory, String listenerBeanName, ResolvableType eventType) {
//获取名字对应的clazz对象
Class<?> listenerType = beanFactory.getType(listenerBeanName);
//监听器的类型为GenericApplicationListener或SmartApplicationListener允许实例化
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;
}
}
/**
* Filter a listener early through checking its generically declared event
* type before trying to instantiate it.
* <p>If this method returns {@code true} for a given listener as a first pass,
* the listener instance will get retrieved and fully evaluated through a
* {@link #supportsEvent(ApplicationListener, ResolvableType, Class)} call afterwards.
* @param listenerType the listener's type as determined by the BeanFactory
* @param eventType the event type to check
* @return whether the given listener should be included in the candidates
* for the given event type
*/
protected boolean supportsEvent(Class<?> listenerType, ResolvableType eventType) {
//早期检查监听器监听的事件类型,见6.3.3
ResolvableType declaredEventType = GenericApplicationListenerAdapter.resolveDeclaredEventType(listenerType);
return (declaredEventType == null || declaredEventType.isAssignableFrom(eventType));
}
6.4 执行监听器
/**
* Invoke the given listener with the given event.
* @param listener the ApplicationListener to invoke
* @param event the current event to propagate
* @since 4.1
*/
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 {
//调用onApplicationEvent方法
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
// -> let's suppress the exception and just log a debug message.
Log logger = LogFactory.getLog(getClass());
if (logger.isTraceEnabled()) {
logger.trace("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}
执行过程很简单,就是直接调用ApplicationListener
接口的onApplicationEvent()
方法
到此为止,基于
XML
方式的监听器工作原理就已经说完了,下一篇文章我们来看基于注解
的监听器是如何工作的。