ApplicationEvent事件机制源码分析
《spring扩展点之三:Spring 的监听事件 ApplicationListener 和 ApplicationEvent 用法,在spring启动后做些事情》
Spring中的监听器模式
1、Spring在事件处理机制中使用了监听器模式,其中的三个主要角色:
- 事件,ApplicationEvent,该抽象类继承了EventObject,EventObject是JDK中的类,并建议所有的事件都应该继承自EventObject。
- 事件监听器,ApplicationListener,是一个接口,该接口继承了EventListener接口。EventListener接口是JDK中的,建议所有的事件监听器都应该继承EventListener。监听器是用于接收事件,并触发事件的操作,这样说起来可能有点费解,简单的说就是,Listener是监听ApplicationContext.publishEvent,方法的调用,一旦调用publishEvent,就会执行ApplicaitonListener中的方法,下面这个是ApplicationContext的源码。
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
/**
* publishEvent触发该方方法
* 可以在该方法中写各种业务逻辑
*/
void onApplicationEvent(E event);
}
- 事件发布,ApplicationEventPublisher,ApplicationContext继承了该接口,在ApplicationContext的抽象实现类AbstractApplicationContext中做了实现。下面会详解。
2、Spring事件发布机制

3、spring中的事件(异步)机制流程
2.1、Spring事件源
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 ApplicationEvent.
* @param source the object on which the event initially occurred (never {@code null})
*/
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
/**
* Return the system time in milliseconds when the event happened.
*/
public final long getTimestamp() {
return this.timestamp;
}
}
2.2、Spring事件监听器
spring-context-4.3.14.RELEASE-sources.jar中的ApplicationListener.java类类
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
/**
* Handle an application event.
* @param event the event to respond to
*/
void onApplicationEvent(E event);
}
jdk中的EventListener.java类是一个空接口
public interface EventListener {
}
2.3、Spring事件发布
spring-context-4.3.14.RELEASE-sources.jar中的ApplicationEventPublisher.java类
public interface ApplicationEventPublisher {
/**
* Notify all <strong>matching</strong> listeners registered with this
* application of an application event. Events may be framework events
* (such as RequestHandledEvent) or application-specific events.
* @param event the event to publish
* @see org.springframework.web.context.support.RequestHandledEvent
*/
void publishEvent(ApplicationEvent event);
/**
* Notify all <strong>matching</strong> listeners registered with this
* application of an event.
* <p>If the specified {@code event} is not an {@link ApplicationEvent},
* it is wrapped in a {@link PayloadApplicationEvent}.
* @param event the event to publish
* @since 4.2
* @see PayloadApplicationEvent
*/
void publishEvent(Object event);
}
AbstractApplicationContext类中publishEvent方法实现:
protected void publishEvent(Object event, ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Publishing event in " + getDisplayName() + ": " + event);
}
// Decorate event as an ApplicationEvent if necessary
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
else {
applicationEvent = new PayloadApplicationEvent<Object>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent) applicationEvent).getResolvableType();
}
}
// Multicast right now if possible - or lazily once the multicaster is initialized
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
//事件委派给ApplicationEventMulticaster来执行
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);
}
}
}
ApplicationEventMulticaster的multicastEvent方法的实现在SimpleApplicationEventMulticaster类中:
@Override
public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
//获得监听器集合,遍历监听器,可支持同步和异步的广播事件
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(new Runnable() {
@Override
public void run() {
invokeListener(listener, event);
}
});
}
else {
invokeListener(listener, event);
}
}
}
invokeListener()方法:

这就执行了ApplicationListener的onApplicationEvent方法,这里是事件发生的地方。
2.4、Spring如何根据事件找到事件对应的监听器
在Spring容器初始化的时候,也就是在AbstractApplicationContext.java在refresh()中:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
......
try {
......
// Initialize event multicaster for this context.
//初始化一个事件注册表
initApplicationEventMulticaster();
......
// Check for listener beans and register them.
//注册事件监听器
registerListeners();
......
}
}
}
也就是在AbstractApplicationContext.java的initApplicationEventMulticaster方法初始化事件注册表
protected void initApplicationEventMulticaster() {
//获得beanFactory
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
//先查找BeanFactory中是否有ApplicationEventMulticaster
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
}
else {//如果BeanFactory中不存在,就创建一个SimpleApplicationEventMulticaster
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
}
}
在SimpleApplicationEventMulticaster在父类AbstractApplicationEventMulticaster类中有如下属性:
//注册表
private final ListenerRetriever defaultRetriever = new ListenerRetriever(false);
//注册表的缓存
private final Map<ListenerCacheKey, ListenerRetriever> retrieverCache = new ConcurrentHashMap<ListenerCacheKey, ListenerRetriever>(64); private BeanFactory beanFactory;
ListenerRetriever.java是一个内部类,主要作用:助手类,它封装特定的目标侦听器集合,允许对预过滤的侦听器进行高效的检索。此助手的实例缓存每个事件类型和源类型。
ListenerRetriever.java的结构如下:
//用来存放监听事件
public final Set<ApplicationListener> applicationListeners;
//存放监听事件的类名称
public final Set<String> applicationListenerBeans; private final boolean preFiltered;
初始化注册表之后,就会把事件注册到注册表中,AbstractApplicationContext.registerListeners():
protected void registerListeners() {
//获取所有的Listener,把事件的bean放到ApplicationEventMulticaster中
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!
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
//把事件的名称放到ApplicationListenerBean里去。
for (String lisName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(lisName);
}
}
Spring使用反射机制,通过方法getBeansOfType获取所有继承了ApplicationListener接口的监听器,然后把监听器放到注册表中,所以我们可以在Spring配置文件中配置自定义监听器,在Spring初始化的时候,会把监听器自动注册到注册表中去。
applicationContext.java中的getBeansOfType(Class<T> type)的实现在
@Override
@SuppressWarnings("unchecked")
public <T> Map<String, T> getBeansOfType(Class<T> type, boolean includeNonSingletons, boolean allowEagerInit)
throws BeansException { boolean isFactoryType = (type != null && FactoryBean.class.isAssignableFrom(type));
Map<String, T> matches = new LinkedHashMap<String, T>(); for (Map.Entry<String, Object> entry : this.beans.entrySet()) {
String beanName = entry.getKey();
Object beanInstance = entry.getValue();
// Is bean a FactoryBean?
if (beanInstance instanceof FactoryBean && !isFactoryType) {
// Match object created by FactoryBean.
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
Class<?> objectType = factory.getObjectType();
if ((includeNonSingletons || factory.isSingleton()) &&
objectType != null && (type == null || type.isAssignableFrom(objectType))) {
matches.put(beanName, getBean(beanName, type));
}
}
else {
if (type == null || type.isInstance(beanInstance)) {
// If type to match is FactoryBean, return FactoryBean itself.
// Else, return bean instance.
if (isFactoryType) {
beanName = FACTORY_BEAN_PREFIX + beanName;
}
matches.put(beanName, (T) beanInstance);
}
}
}
return matches;
}
反射的见《instanceof, isinstance,isAssignableFrom的区别》
ApplicationContext发布事件可以参考上面的内容。发布事件的时候的一个方法,getApplicationListeners:
protected Collection<ApplicationListener> getApplicationListeners(ApplicationEvent event) {
//获取事件类型
Class<? extends ApplicationEvent> eventType = event.getClass();
//或去事件源类型
Class sourceType = event.getSource().getClass();
ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
//从缓存中查找ListenerRetriever
ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
//缓存中存在,直接返回对应的Listener
if (retriever != null) {
return retriever.getApplicationListeners();
}
else {//缓存中不存在,就获取相应的Listener
retriever = new ListenerRetriever(true);
LinkedList<ApplicationListener> allListeners = new LinkedList<ApplicationListener>();
Set<ApplicationListener> listeners;
Set<String> listenerBeans;
synchronized (this.defaultRetriever) {
listeners = new LinkedHashSet<ApplicationListener>(this.defaultRetriever.applicationListeners);
listenerBeans = new LinkedHashSet<String>(this.defaultRetriever.applicationListenerBeans);
}
//根据事件类型,事件源类型,获取所需要的监听事件
for (ApplicationListener listener : listeners) {
if (supportsEvent(listener, eventType, sourceType)) {
retriever.applicationListeners.add(listener);
allListeners.add(listener);
}
}
if (!listenerBeans.isEmpty()) {
BeanFactory beanFactory = getBeanFactory();
for (String listenerBeanName : listenerBeans) {
ApplicationListener listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class);
if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
retriever.applicationListenerBeans.add(listenerBeanName);
allListeners.add(listener);
}
}
}
OrderComparator.sort(allListeners);
this.retrieverCache.put(cacheKey, retriever);
return allListeners;
}
}
根据事件类型,事件源类型获取所需要的监听器supportsEvent(listener, eventType, sourceType):
protected boolean supportsEvent(ApplicationListener<?> listener, ResolvableType eventType, Class<?> sourceType) {
GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}
这里没有进行实际的处理,实际处理在smartListener.supportsEventType(eventType)和smartListener.supportsSourceType(sourceType)方法中。
smartListener.supportsEventType(eventType):
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
Class typeArg = GenericTypeResolver.resolveTypeArgument(this.delegate.getClass(), ApplicationListener.class);
if (typeArg == null || typeArg.equals(ApplicationEvent.class)) {
Class targetClass = AopUtils.getTargetClass(this.delegate);
if (targetClass != this.delegate.getClass()) {
typeArg = GenericTypeResolver.resolveTypeArgument(targetClass, ApplicationListener.class);
}
}
return (typeArg == null || typeArg.isAssignableFrom(eventType));
}
该方法主要的逻辑就是根据事件类型判断是否和监听器参数泛型的类型是否一致。
smartListener.supportsSourceType(sourceType)方法的实现为:
public boolean supportsSourceType(Class<?> sourceType) {
return true;
}
定义自己的监听器要明确指定参数泛型,表明该监听器支持的事件,如果不指明具体的泛型,则没有监听器监听事件。
ApplicationEvent事件机制源码分析的更多相关文章
- React 为什么要把事件挂载到 document 上 & 事件机制源码分析
前言 我们都知道 React 组件绑定事件的本质是代理到 document 上,然而面试被问到,为什么要这么设计,有什么好处吗? 我知道肯定不会是因为虚拟 DOM 的原因,因为 Vue 的事件就能挂载 ...
- Android事件分发机制源码分析
Android事件分发机制源码分析 Android事件分发机制源码分析 Part1事件来源以及传递顺序 Activity分发事件源码 PhoneWindow分发事件源码 小结 Part2ViewGro ...
- SpringBoot事件监听机制源码分析(上) SpringBoot源码(九)
SpringBoot中文注释项目Github地址: https://github.com/yuanmabiji/spring-boot-2.1.0.RELEASE 本篇接 SpringApplicat ...
- Springboot学习04-默认错误页面加载机制源码分析
Springboot学习04-默认错误页面加载机制源码分析 前沿 希望通过本文的学习,对错误页面的加载机制有这更神的理解 正文 1-Springboot错误页面展示 2-Springboot默认错误处 ...
- Zepto事件模块源码分析
Zepto事件模块源码分析 一.保存事件数据的handlers 我们知道js原生api中要移除事件,需要传入绑定时的回调函数.而Zepto则可以不传入回调函数,直接移除对应类型的所有事件.原因就在于Z ...
- Android查缺补漏(View篇)--事件分发机制源码分析
在上一篇博文中分析了事件分发的流程及规则,本篇会从源码的角度更进一步理解事件分发机制的原理,如果对事件分发规则还不太清楚的童鞋,建议先看一下上一篇博文 <Android查缺补漏(View篇)-- ...
- 【Cocos2d-x 3.x】 事件处理机制源码分析
在游戏中,触摸是最基本的,必不可少的.Cocos2d-x 3.x中定义了一系列事件,同时也定义了负责监听这些事件的监听器,另外,cocos定义了事件分发类,用来将事件派发出去以便可以实现相应的事件. ...
- hadoop的RPC机制 -源码分析
这些天一直奔波于长沙和武汉之间,忙着腾讯的笔试.面试,以至于对hadoop RPC(Remote Procedure Call Protocol ,远程过程调用协议,它是一种通过网络从远程计算机程序上 ...
- Hadoop的RPC机制源码分析
分析对象: hadoop版本:hadoop 0.20.203.0 必备技术点: 1. 动态代理(参考 :http://www.cnblogs.com/sh425/p/6893662.html )2. ...
随机推荐
- 面试题2:单例模式Singleton
首先,单例模式使类在程序生命周期的任何时刻都只有一个实例, 然后,单例的构造函数是私有的,外部程序如果想要访问这个单例类的话, 必须通过 getInstance()来请求(注意是请求)得到这个单例类的 ...
- sublime text3的快捷键
Ctrl + Shift + P 调出命令板(Command Palette) Ctrl + ` 调出控制台 Ctrl + D 选择当前光标所在的词并高亮该词所有出现的位置,再次 C ...
- L1-041 寻找250
对方不想和你说话,并向你扔了一串数…… 而你必须从这一串数字中找到“250”这个高大上的感人数字. 输入格式: 输入在一行中给出不知道多少个绝对值不超过1000的整数,其中保证至少存在一个“250”. ...
- 关于LUN和卷的思考
LUN:logical unit number 是指硬件层分出的逻辑盘,OS仍然把这些逻辑盘看成是物理盘. 例如将一个1PB磁盘柜划分为100个相同大小的lun,那么每个lun的大小就是10TB,lu ...
- JavaWeb中监听器+过滤器+拦截器区别、配置和实际应用
JavaWeb中监听器+过滤器+拦截器区别.配置和实际应用 1.前沿上一篇文章提到在web.xml中各个元素的执行顺序是这样的,context-param-->listener-->fil ...
- Docker教程-01.安装docker-ce-18.06
参考文章:http://www.runoob.com/docker/docker-tutorial.html 1.Docker简介 1)Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 ...
- hive中实现类似MySQL中的group_concat功能
hive> desc t; OK id string str string Time taken: 0.249 seconds hive> select * from t ...
- (3)什么是函数(函数的定义、形参、实参、默认形参、可变长函数args|kwargs)
什么是函数 函数是指将一组语句的集合通过一个名字(函数名)封装起来,想要执行这个函数,只需调用其函数名即可 1.减少重复代码 2.使程序变的可扩展 3.使程序变得易维护 定义函数的语法 形参 主要的作 ...
- CountDownLatch的简单理解
CountDownLatch的概念 CountDownLatch是一个同步工具类,用来协调多个线程之间的同步,或者说起到线程之间的通信(而不是用作互斥的作用). CountDownLatch能够使一个 ...
- 手把手图文教你eclipse下如何配置tomcat
很多初学,尤其自学JavaWeb的朋友首次在eclipse下配置tomcat时,总会有种难下手的感觉,在此,笔者通过图文解说的方法,最直观的向大家演示一遍该配置过程,希望对大家有所帮助. 注:本文是建 ...