Spring事件驱动模型与工程中的使用
本文参考开涛博客链接
事件驱动模型简介
事件驱动模型也就是我们常说的观察者,或者发布-订阅模型,简单理解:
- 首先是一种对象间的一对多的关系;例如交通信号灯,信号灯是目标(一方),行人注视着信号灯(多方);
- 当目标发生改变(发布),观察者(订阅者)就可以接收到改变;
- 观察者如何处理(行人如何行走,是快/慢/不走,目标不管),目标不干涉,松耦合了他们之间的关系
接下来看一个用户注册的例子:
用户注册成功后,其他操作:
1. 添加积分
2. 发确认邮件
3. 发送游戏礼包
4. 索引用户数据
……
问题
- UserService与其他Service耦合严重,增删比较麻烦
- 有些功能可能调用第三方系统,速度较慢,需要异步支持
- 有些功能与主要业务不想关,比如日志,可以异步处理,快速返回
从以上例子看出,应该使用一个观察者来解耦这些Service之间的依赖关系,如图:
增加了一个Listener来解耦UserService和其他服务,即注册成功后,只需要通知相关的监听器,不需要关心他们如何处理。
这是一个典型的事件处理模型/观察者,解耦目标对象和它的依赖对象,目标只需要通知它的依赖对象,具体怎么处理,依赖对象自己决定。
上边其实也使用了DIP(依赖倒置原则),依赖于抽象,而不是具体。还有就是IOC思想,即以前主动去创建依赖的Service,现在只是被动等待别人注入进来
Spring提供的事件驱动模型/观察者抽象
首先看下Spring提供的事件驱动模型:
事件
具体实现:ApplicationEvent:
- 继承自JDK的EventObject,JDK要求所有事件都继承它,并通过source得到事件源
- 系统默认提供了如下ApplicationEvent事件实现:
只有一个ApplicationContextEvent,表示ApplicationContext容器事件,且其又有如下实现: - ContextStartedEvent:ApplicationContext启动后触发的事件;
- ContextStopedEvent:ApplicationContext停止后触发的事件;
- ContextRefreshedEvent:ApplicationContext初始化或刷新完成后触发的事件;(容器初始化完成后调用)
- ContextClosedEvent:ApplicationContext关闭后触发的时间(如web容器关闭时自动会触发Spring容器的关闭,如果是普通java应用,需要调用ctx.registerShutdownHook();注册虚拟机关闭时的钩子才行)
目标(事件发布者)
具体代表者是:ApplicationEventPublisher及ApplicationEventMulticaster,系统提供了默认实现:
- ApplicationContext接口继承了ApplicationEventPublisher,并在AbstractApplicationContext实现了具体代码,实际执行是委托给了ApplicationEventMulticaster(可以认为是多播):
/**
* 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)
*/
public void publishEvent(ApplicationEvent event) {
......
getApplicationEventMulticaster().multicastEvent(event);
if (this.parent != null) {
this.parent.publishEvent(event);
}
}
我们常用的ClassPathXmlApplicationContext、XmlWebApplicationContext等继承AbstractApplicationContext,所以自动拥有这功能。
2.ApplicationContext自动到本地容器里找一个名字为ApplicationEventMultcaster实现,如果没有自己new一个SimpleApplicationEventMulticaster,其中SimpleApplicationEventMulticaster发布事件的代码:
public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
......
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);
}
}
}
如果给它一个executor,他就可以异步支持发布事件,否则就是同步发送。
监听器
具体代表者是ApplicationListener:
- 继承自JDK的EventListener,JDK要求所有监听器继承它
- ApplicationListener接口:
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
void onApplicationEvent(E event);
}
其只提供了onApplicationEvent方法,我们需要在该方法实现内部判断事件类型来处理,也没有提供按顺序触发监听器的语义,所以Spring提供了另一个借口SmartApplicationListener:
public interface SmartApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered {
// 如果实现支持该事件类型,那么返回true
boolean supportsEventType(Class<? extends ApplicationEvent> eventType);
// 如果实现支持"目标"类型,那么返回true
boolean supportsSourceType(Class<?> sourceType);
}
该接口可方便实现去判断支持的时间类型、目标类型