Spring 事件框架 ApplicationEvent & 观察者模式(Publisher -> Listener)
Event 事件机制概述
事件机制在一些大型项目中被经常使用,于是 Spring 专门提供了一套事件机制的接口,方便我们运用。本文来说说 ApplicationEventPublisher 的使用。
在设计模式中,观察者模式可以算得上是一个非常经典的行为型设计模式.
java 和 spring 中都拥有 Event 的抽象,分别代表了语言级别和三方框架级别对事件的支持。
Spring 的文档对 Event 的支持翻译之后描述如下:
ApplicationContext 通过 ApplicationEvent 类和 ApplicationListener 接口进行事件处理。 如果将实现 ApplicationListener 接口的 bean 注入到上下文中,则每次使用 ApplicationContext 发布 ApplicationEvent 时,都会通知该 bean。本质上,这是标准的观察者设计模式。
ApplicationEvent 是由 Spring 提供的所有 Event 类的基类,为了简单起见,注册事件只传递了 name(可以复杂的对象,但注意要了解清楚序列化机制)。
需要注意的是,服务必须交给 Spring 容器托管。ApplicationEventPublisherAware 是由 Spring 提供的用于为 Service 注入 ApplicationEventPublisher 事件发布器的接口,使用这个接口,我们自己的 Service 就拥有了发布事件的能力。用户注册后,不再是显示调用其他的业务 Service,而是发布一个用户注册事件。
事件订阅者的服务同样需要托管于 Spring 容器,ApplicationListener 接口是由 Spring 提供的事件订阅者必须实现的接口,我们一般把该 Service 关心的事件类型作为泛型传入。处理事件,通过 event.getSource() 即可拿到事件的具体内容.
核心类说明
1.ApplicationEventPublisherAware
ApplicationEventPublisherAware 是由 Spring 提供的用于为 Service 注入 ApplicationEventPublisher 事件发布器的接口. 使用这个接口,我们自己的 Service 就拥有了发布事件的能力。用户注册后,不再是显示调用其他的业务 Service,而是发布一个用户注册事件。
2.ApplicationListener
ApplicationListener接口是由 Spring 提供的事件订阅者必须实现的接口,我们一般把该 Service 关心的事件类型作为泛型传入。
处理事件: 通过 event.getSource() 即可拿到事件的具体内容
3.ApplicationEventPublisher
ApplicationEventPublisher是ApplicationContext的父接口之一。这接口的作用是:Interface that encapsulates event publication functionality.
功能: 发布事件,也就是把某个事件告诉的所有与这个事件相关的监听器。
下面看一个 ApplicationEventPublisher 的使用实例。
/**
* 事件基类
*/
public class KunLunEvent extends ApplicationEvent {
private TaskInstanceDTO taskInstanceDTO;
private EventType eventType;
public KunLunEvent(Object source, TaskInstanceDTO taskInstanceDTO) {
super(source);
this.taskInstanceDTO=taskInstanceDTO;
}
public TaskInstanceDTO getTaskInstance(){
return taskInstanceDTO;
}
public EventType getEventType() {
return eventType;
}
public void setEventType(EventType eventType) {
this.eventType = eventType;
}
}
/**
*事件处理器
*/
public interface KunLunHandler {
/**
*处理具体业务逻辑
* @param kunLunEvent
*/
void handle(KunLunEvent kunLunEvent);
Boolean match(KunLunEvent kunLunEvent);
}
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.util.List;
/**
*事件监听器
*/
@Component
public class KunLunListener {
@Resource
List handlerList;
@Async
@EventListener
public void onApplicationEvent(KunLunEvent kunLunEvent) {
if(!CollectionUtils.isEmpty(handlerList)){
handlerList.stream()
.filter(handler -> handler.match(kunLunEvent))
.forEach(handler -> handler.handle(kunLunEvent));
}
}
}
具体的Handler 实现:
@Service
public class CrowdHiveResultHandler implements KunLunHandler {}
@Service
public class CrowdAbaseResultHandler implements KunLunHandler {}
事件发布器
@Service
public class DoradoWebHookServiceImpl implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void handle() {
// ….
// 推送异步消息
publishEvent(doradoWebHookResponse);
}
/**
*发送异步消息
*/
private void publishEvent() {
// …
applicationContext.publishEvent(event);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}