"Spring 事件"(Spring events)属于spirng core,是一种观察者设计模式的实现,用于在应用程序中处理事件通知。在 Spring Framework 中,事件是指应用程序中发生的特定动作或状态更改。那么什么是观察者模式呢?
观察者模式是一种行为设计模式, 允许你定义一种订阅机制, 可在对象事件发生时通知多个 “观察” 该对象的其他对象。
假如你有两种类型的对象:顾客和商店,顾客对某个特定品牌的产品非常感兴趣 (例如最新型号的 iPhone 手机), 而该产品很快将会在商店里出售。
顾客可以每天来商店看看产品是否到货。 但如果商品尚未到货时, 绝大多数来到商店的顾客都会空手而归。
另一方面, 每次新产品到货时, 商店可以向所有顾客发送邮件 (可能会被视为垃圾邮件)。 这样, 部分顾客就无需反复前往商店了, 但也可能会惹恼对新产品没有兴趣的其他顾客。
我们似乎遇到了一个矛盾: 要么让顾客浪费时间检查产品是否到货, 要么让商店浪费资源去通知没有需求的顾客。
拥有一些值得关注的状态的对象通常被称为目标, 由于它要将自身的状态改变通知给其他对象, 我们也将其称为发布者 (publisher)。 所有希望关注发布者状态变化的其他对象被称为订阅者 (subscribers)。
还是已上面的例子,想要买手机的顾客此刻成为订阅者,商店测试就是发布者,手机到货就是一个事件,此时商店只需要把邮件发给订阅了这个事件的顾客,顾客就能收到邮件,就回来买手机,此时既不需要浪费顾客时间,也不会浪费商店资源。
观察者设计模式就会包含这么几个元素:
发布者 (Publisher) 会向其他对象发送值得关注的事件。 事件会在发布者自身状态改变或执行特定行为后发生。 发布者中包含一个允许新订阅者加入和当前订阅者离开列表的订阅构架。
订阅者 (Subscriber) 接口声明了通知接口。 在绝大多数情况下, 该接口仅包含一个update更新方法。 该方法可以拥有多个参数, 使发布者能在更新时传递事件的详细信息。
具体订阅者 (Concrete Subscribers) 可以执行一些操作来回应发布者的通知。 所有具体订阅者类都实现了同样的接口, 因此发布者不需要与具体类相耦合。
客户端 (Client) 会分别创建发布者和订阅者对象, 然后为订阅者注册发布者更新。
放个原理图
再回过头来说说spring的事件,通常涉及到几个关键组件:
事件(Event): 事件是一个对象,用于封装有关事件的信息。可以创建自定义事件类,以便携带特定的数据。
事件发布者(Event Publisher): 事件发布者负责发布(触发)事件。在 Spring 中,通常是某个对象拥有发布事件的能力。
事件监听器(Event Listener): 事件监听器是一个或多个对象,它们注册对特定事件的兴趣,并在事件发生时执行相应的操作。
结合上文中顾客去商店买手机的例子就很好理解了。
还是顾客去商店买手机的例子,我们编写大致流程:
手机到货事件
/**
* 创建一个手机到货的事件,继承ApplicationEvent
*/
public class PhoneEvent extends ApplicationEvent {
/**
* 到货通知
*/
public String arrivalNotice;
public PhoneEvent(String source) {
super(source);
this.arrivalNotice = source;
}
public String getArrivalNotice() {
return arrivalNotice;
}
public void setArrivalNotice(String arrivalNotice) {
this.arrivalNotice = arrivalNotice;
}
}
顾客订阅了到货事件
/**
* 相当于订阅者
*/
@Component
public class PhoneEventListener {
/**
* 监听手机到货的事件
*
* @param event
*/
@EventListener
public void listener(PhoneEvent event) {
System.out.println("收到商店的邮件:" + event.getArrivalNotice());
}
}
如果手机到货了,那商店就会发布一个事件
/**
* 这是商店发布的事件
*/
@Service
public class PublishEventService {
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
public void publishEvent(String phoneType) {
String msg = "";
if ("1".equals(phoneType)) {
msg="华为到货了";
}else if ("2".equals(phoneType)){
msg="小米到货了";
}else if ("3".equals(phoneType)){
msg="vivo到货了";
}else if ("4".equals(phoneType)){
msg="oppo到货了";
}else if ("5".equals(phoneType)){
msg="魅族到货了";
}else if ("6".equals(phoneType)){
msg="三星到货了";
}else if ("7".equals(phoneType)){
msg="一加到货了";
}else if ("8".equals(phoneType)){
msg="苹果到货了";
}else {
msg="箱子是空的";
}
applicationEventPublisher.publishEvent(new PhoneEvent(msg));
}
}
然后我们手动写一个controller来模拟手机到货,并输入到货的型号
/**
* 模拟手机到货
*/
@RestController
public class EventController {
@Autowired
private PublishEventService publishEvent;
/**
* 手动触发手机到货事件
*
* @param phoneType 手机类型
*/
@GetMapping("/phone/{phoneType}")
public void phone(@PathVariable("phoneType") String phoneType) {
publishEvent.publishEvent(phoneType);
}
}
启动springboot项目,并向接口/phone/1发送一个GET请求,然后把1替换成其他数字
我们查看控制台输出
此时说明了顾客监听到了商店发布的手机到货的事件。这就是spring的事件机制了。
当发布一个事件的时候,系统就会去找到所有合适的事件消费者,然后去调用这些事件消费者
参考:Spring 中的事件(Event)机制 - spring 中文网 (springdoc.cn)