
众所周知,spring framework在 beanfactory的基础容器之上扩展为了applicationcontext上下文。 applicationcontext处理包含了beanfactory的全部基础功能之外,还额外提供了大量的扩展功能。

今天我们就来看看 扩展的 事件监听接口
概述
我们都知道 实现事件监听机制至少四个组成部分:
- 事件
- 事件生产者
- 事件消费者
- 控制器 (管理生产者、消费者和事件之间的注册监听关系)
在spring中,事件监听机制主要实现是通过事件、事件监听器、事件发布者和事件广播器来实现。
applicationevent ------ 事件

public abstract class applicationcontextevent extends applicationevent {
/**
* create a new contextstartedevent.
* @param source the {@code applicationcontext} that the event is raised for
* (must not be {@code null})
*/
public applicationcontextevent(applicationcontext source) {
super(source);
}
/**
* get the {@code applicationcontext} that the event was raised for.
*/
public final applicationcontext getapplicationcontext() {
return (applicationcontext) getsource();
}
}
抽象父类applicationevent,它的子抽象类applicationcontextevent 包含有当前applicationcontext的引用,这样就可以确认每个事件是从哪一个spring容器中发生的。
applicationlistener ------ 事件监听器
顶级接口applicationlistener,只有一个void onapplicationevent(e event); ,当该监听器所监听的事件发生时,就会执行该方法
applicationeventpublisher ------ 事件发布者
顶级接口applicationeventpublisher,只有一个方法 void publishevent(object event); ,调用该方法就可以发生spring中的事件
applicationeventmulticaster ------ 事件广播器
spring中的事件核心控制器叫做事件广播器,两个作用
将事件监听器注册到广播器中
这样广播器就知道了每个事件监听器分别监听什么事件,且知道了每个事件对应哪些事件监听器在监听。
将事件广播给事件监听器
当有事件发生时,需要通过广播器来广播给所有的事件监听器,因为生产者只需要关心事件的生产,而不需要关心该事件都被哪些监听器消费。
spring主要的内置事件
contextrefreshedevent
applicationcontext 被初始化或刷新时,该事件被发布。
也可以在configurableapplicationcontext接口中使用 refresh()方法来发生。
此处的初始化是指:所有的bean被成功装载,后处理bean被检测并激活,所有singleton bean 被预实例化,applicationcontext容器已就绪可用。
contextstartedevent
当使用 configurableapplicationcontext 接口中的 start() 方法启动 applicationcontext时,该事件被发布。
可以在接受到这个事件后重启任何停止的应用程序。
contextstoppedevent
当使用 configurableapplicationcontext接口中的 stop()停止applicationcontext 时,发布这个事件。
可以在接受到这个事件后做必要的清理的工作
contextclosedevent
当使用 configurableapplicationcontext接口中的 close()方法关闭 applicationcontext 时,该事件被发布。
一个已关闭的上下文到达生命周期末端;它不能被刷新或重启
requesthandledevent
这是一个 web-specific 事件,告诉所有 bean http 请求已经被服务。只能应用于使用dispatcherservlet的web应用。
在使用spring作为前端的mvc控制器时,当spring处理用户请求结束后,系统会自动触发该事件
org.springframework.context.applicationlistener
@functionalinterface
public interface applicationlistener<e extends applicationevent> extends eventlistener {
/**
* handle an application event.
* @param event the event to respond to
*/
void onapplicationevent(e event);
/**
* create a new {@code applicationlistener} for the given payload consumer.
* @param consumer the event payload consumer
* @param <t> the type of the event payload
* @return a corresponding {@code applicationlistener} instance
* @since 5.3
* @see payloadapplicationevent
*/
static <t> applicationlistener<payloadapplicationevent<t>> forpayload(consumer<t> consumer) {
return event -> consumer.accept(event.getpayload());
}
}

applicationlistener可以监听某个事件的event,触发时机可以穿插在业务方法执行过程中,用户可以自定义某个业务事件。
源码分析
首先看看spring在初始化的时候,有两个核心步骤和事件监听器有关,一个是初始化事件广播器,一个是注册所有的事件监听器
org.springframework.context.support.abstractapplicationcontext#refresh
@override
public void refresh() throws beansexception, illegalstateexception {
synchronized (this.startupshutdownmonitor) {
// initialize event multicaster for this context.
initapplicationeventmulticaster();
// check for listener beans and register them.
registerlisteners();
}
初始化事件广播器
/** spring容器的事件广播器对象*/
private applicationeventmulticaster applicationeventmulticaster;
/** 事件广播器对应的beanname*/
public static final string application_event_multicaster_bean_name = "applicationeventmulticaster";
/** 初始化事件广播器*/
protected void initapplicationeventmulticaster() {
//1.获取spring容器beanfactory对象
configurablelistablebeanfactory beanfactory = getbeanfactory();
//2.从beanfactory获取事件广播器的bean,如果存在说明是用户自定义的事件广播器
if (beanfactory.containslocalbean(application_event_multicaster_bean_name)) {
//2.1.给容器的事件广播器赋值
this.applicationeventmulticaster =
beanfactory.getbean(application_event_multicaster_bean_name, applicationeventmulticaster.class);
if (logger.istraceenabled()) {
logger.trace("using applicationeventmulticaster [" + this.applicationeventmulticaster + "]");
}
}
else {
//3.如果没有自定义的,则初始化默认的事件广播器simpleapplicationeventmulticaster对象
this.applicationeventmulticaster = new simpleapplicationeventmulticaster(beanfactory);
//4.注册该bean
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() + "]");
}
}
}
如果beanfactory中存在用于自定义的就使用自定义的,如果没有自定义的就创建新的默认的事件广播器simpleapplicationeventmulticaster对象,然后赋值给applicationeventmulticaster对象。
注册事件监听器
/** 注册事件监听器*/
protected void registerlisteners() {
//1.遍历将通过编码方式创建的事件监听器加入到事件广播器中
for (applicationlistener<?> listener : getapplicationlisteners()) {
//2.获取到当前事件广播器,添加事件监听器
getapplicationeventmulticaster().addapplicationlistener(listener);
}
//3.从beanfactory中获取所有实现了applicationlistener接口的bean,遍历加入到事件广播器中
string[] listenerbeannames = getbeannamesfortype(applicationlistener.class, true, false);
for (string listenerbeanname : listenerbeannames) {
getapplicationeventmulticaster().addapplicationlistenerbean(listenerbeanname);
}
//3.获取需要提前发布的事件
set<applicationevent> earlyeventstoprocess = this.earlyapplicationevents;
this.earlyapplicationevents = null;
if (earlyeventstoprocess != null) {
for (applicationevent earlyevent : earlyeventstoprocess) {
//5.遍历将提前发布的事件广播出去
getapplicationeventmulticaster().multicastevent(earlyevent);
}
}
从容器中找到所有的事件监听器,然后调用事件广播器的addapplicationlistener方法将事件监听器添加到事件广播器中。

事件的发布和消费

事件的发布是通过applicationeventpublisher的实现类实现的publishevent方法实现的,applicationcontext就实现了该接口,所以使用spring时就可以直接使用applicationcontext实例来调用publishevent方法来发布事件
/** 发布事件
* @param event:事件对象
* */
@override
public void publishevent(object event) {
publishevent(event, null);
}
/** 发布事件
* @param event:事件对象
* @param eventtype:事件类型
* */
protected void publishevent(object event, @nullable resolvabletype eventtype) {
assert.notnull(event, "event must not be null");
/** 1.将发布的事件封装成applicationevent对象(因为传入的参数是object类型,有可能没有继承applicationevent) */
applicationevent applicationevent;
if (event instanceof applicationevent) {
applicationevent = (applicationevent) event;
}
else {
applicationevent = new payloadapplicationevent<>(this, event);
if (eventtype == null) {
eventtype = ((payloadapplicationevent<?>) applicationevent).getresolvabletype();
}
}
if (this.earlyapplicationevents != null) {
/** 2.1.如果需要提前发布的事件还没有发布完,则不是立即发布,而是将事件加入到待发布集合中*/
this.earlyapplicationevents.add(applicationevent);
}
else {
/** 2.2.获取当前的事件广播器,调用multicasterevent方法广播事件*/
getapplicationeventmulticaster().multicastevent(applicationevent, eventtype);
}
/** 3.如果当前applicationcontext有父类,则再调用父类的publishevent方法*/
if (this.parent != null) {
if (this.parent instanceof abstractapplicationcontext) {
((abstractapplicationcontext) this.parent).publishevent(event, eventtype);
}
else {
this.parent.publishevent(event);
}
}
}
首先是将发布的事件转化成applicationevent对象,然后获取到事件广播器,调用事件广播器的multicastevent方法来广播事件,所以核心逻辑又回到了事件广播器那里
/** 广播事件
* @param event:事件
* @param eventtype:事件类型
* */
@override
public void multicastevent(final applicationevent event, @nullable resolvabletype eventtype) {
resolvabletype type = (eventtype != null ? eventtype : resolvedefaulteventtype(event));
executor executor = gettaskexecutor(); // (如果有executor,则广播事件就是通过异步来处理的)
/**
* 1.根据事件和类型调用getapplicationlisteners方法获取所有监听该事件的监听器
* */
for (applicationlistener<?> listener : getapplicationlisteners(event, type)) {
if (executor != null) {
/** 2. 异步遍历执行invokelistener方法来唤醒监听器处理事件 */
executor.execute(() -> invokelistener(listener, event));
}
else {
invokelistener(listener, event);
}
}
}
这里主要有两个核心步骤,
- 首先是根据事件和类型找到监听了该事件的所有事件监听器
- 然后遍历来执行监听器的处理逻辑.另外如果配置了执行器executor,就会通过executor来异步发布事件给监听器
根据事件获取事件监听器
protected collection<applicationlistener<?>> getapplicationlisteners(
applicationevent event, resolvabletype eventtype) {
object source = event.getsource();
class<?> sourcetype = (source != null ? source.getclass() : null);
listenercachekey cachekey = new listenercachekey(eventtype, sourcetype);
// quick check for existing entry on concurrenthashmap...
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)))) {
// fully synchronized building and caching of a 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 {
// no listenerretriever caching -> no synchronization necessary
return retrieveapplicationlisteners(eventtype, sourcetype, null);
}
}
核心方法是retrieveapplicationlisteners(eventtype, sourcetype, retriever)方法,源码如下:
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) {
listeners = new linkedhashset<>(this.defaultretriever.applicationlisteners);
listenerbeans = new linkedhashset<>(this.defaultretriever.applicationlistenerbeans);
}
// add programmatically registered listeners, including ones coming
// 遍历所有监听器,调用supportsevent判断是否监听该事件
for (applicationlistener<?> listener : listeners) {
if (supportsevent(listener, eventtype, sourcetype)) {
if (retriever != null) {
retriever.applicationlisteners.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();
//
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 {
// 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) {
retriever.applicationlisteners.remove(listener);
}
alllisteners.remove(listener);
}
}
catch (nosuchbeandefinitionexception ex) {
// singleton listener instance (without backing bean definition) disappeared -
// probably in the middle of the destruction phase
}
}
}
/** 将所有监听器根据order进行排序*/
annotationawareordercomparator.sort(alllisteners);
if (retriever != null && retriever.applicationlistenerbeans.isempty()) {
retriever.applicationlisteners.clear();
retriever.applicationlisteners.addall(alllisteners);
}
return alllisteners;
}
核心步骤:
- 1:获取事件广播器中所有的事件监听器
- 2:遍历事件监听器,判断该监听器是否监听当前事件
- 3:将所有监听当前事件的监听器进行排序
第二步判断监听器是否监听事件的判断,主要是通过反射获取该监听器实现的接口泛型类,如果包含当前事件的类则表示监听,否则就表示不监听
唤醒监听器处理事件
protected void invokelistener(applicationlistener<?> listener, applicationevent event) {
errorhandler errorhandler = geterrorhandler();
if (errorhandler != null) {
try {
/** 调用doinvokelistener方法*/
doinvokelistener(listener, event);
}
catch (throwable err) {
errorhandler.handleerror(err);
}
}
else {
/** 调用doinvokelistener方法*/
doinvokelistener(listener, event);
}
}
继续
private void doinvokelistener(applicationlistener listener, applicationevent event) {
try {
/** 直接调用applicationlistener的onapplicationevent(event)方法*/
listener.onapplicationevent(event);
}
catch (classcastexception ex) {
}
}
直接调用监听器的onapplicationevent方法
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论