Spring事件,ApplicationEvent在业务中的应⽤
前⾔
关于事件驱动模型,百度百科在有明确的解释。在JDK的Util包⾥抽象了事件驱动,有兴趣的朋友可以⾃⾏去看下相关类的定义。Spring事件模
型ApplicationEvent是基于JDK⾥的事件模型,废话不多说,直接看Spring是如何定义事件模型,以及在具体业务场景中的应⽤。
事件
事件就是事件,⿏标点击⼀下算⼀个事件,某个按钮被点击了⼀下算⼀个点击事件,那么我订单⽀付了可以认为⽀付也算⼀个件事!触发了某个事件...... 等等。
抽象类ApplicationEvent承载着我们要传播的事件或者消息,⽩话就是说可以把某个对象⽤ApplicationEvent这个对象来⾥的Source来引⽤。
监听者
上⾯我们定义了事件,那么事件产⽣的⼀系列的效应或者是变动,那么都由这些监听者们去实现。点击下⿏标(事件),那么我记录下⽇志,你弹出个提⽰框。⽀付某个订单(事件),我记录下记录,他发送个⽀
付通知...... 等等。
泛型接⼝ApplicationListener规定了泛型E的上边界为ApplicationEvent,意思很明确,就是给我们⾃定义事件⽤的。Spring最⼤的优点我认为是留给⽤户发挥的空间很⼤,就像神秘的海洋⼀样,它⼀直有你探索不完的秘密,每⼀次你去了解它,它都能给你带来新的事物和理解。
实战
⽂章中,我们⽤SpringPlugin插件的⽅式去实现了订单的不同操作!⽽在某个操作⾥⾯,我们可能⼜要发送操作事件的通知,⽐如:订单⽀付了后,要通知打印机打印⼩票、提醒⽀付信息等等。那么我们来实际的操作下。
定义事件源
public class OrderPayedEvent extends ApplicationEvent {
/**
* 消息体,这⾥就设定为当前订单对象
*/
private final Order order;
public OrderPayedEvent(Object source) {
super(source);
}
springframework事务public Order getOrder() {
return order;
}
}
实现ApplicationEvent,我这⾥Source实际传递就是Order对象,当然你也可以定义其他的多参数构造函数!
定义监听者
定义监听者的⽅式,Spring提供了两种,⼀种是接⼝⽅式,⼀种是注解⽅式。
接⼝⽅式
@Component
@Order(1)
public class OrderPayedPrinterListener implements ApplicationListener<OrderPayedEvent> {
@Override
public void onApplicationEvent(OrderPayedEvent event) {
System.out.printf("【线程 - %s 】订单成功成功:第⼀步,打印⼩票%n", Thread.currentThread().getName());
}
}
@Component
@Order(2)
public class OrderPayedSendMessageListener implements ApplicationListener<OrderPayedEvent> {
@Override
public void onApplicationEvent(OrderPayedEvent event) {
System.out.printf("【线程 - %s 】订单成功成功:第⼆步,发送通知商品中⼼添加库存%n", Thread.currentThread().getName());
}
}
这⾥我定义了两个监听者,实现泛型接⼝ApplicationListener类型为我们刚定义的OrderPayedEvent这⾥加上Order注解,是因为我们有多个监听者,有此业务场景中可能会有顺序的要求!
注解⽅式
@Component
public class OrderPayListener {
@EventListener(classes = {OrderPayedEvent.class})
public void sendTips(OrderPayedEvent event) {
System.out.printf("【线程 - %s 】订单成功成功:发送⽤户订单⽀付消息%n", Thread.currentThread().getName());
}
@EventListener(classes = {OrderPayedEvent.class})
public void reward(OrderPayedEvent event) {
System.out.printf("【线程 - %s 】订单成功成功:奖励业务%n", Thread.currentThread().getName());
}
}
两种⽅式,各有千秋,不同业务场景选择不同实现⽅式即可。但注解⽅式是不会有排序功能的,如果你有业务有需要排序,那么建议换成接⼝⽅式
发布件事
万事具备,只⽋东风。那么只要合适的位置发布事件即可,那么在上回⽂章中的⽀付成功代码加上事件即可
@Component
public class PayOperator implements OrderOperatorPlugin {
//这⾥注⼊应⽤上下⽂,可以注⼊ applicationEventPublisher
@Resource
ApplicationContext context;
// @Resource
// ApplicationEventPublisher applicationEventPublisher;
@Override
public Optional<?> apply(OrderOperatorDTO operator) {
//⽀付操作
//doPay()
//发送事件
context.publishEvent(new OrderPayedEvent(new Order()));
return Optional.of("⽀付成功");
}
@Override
public boolean supports(OrderOperatorDTO operatorDTO) {
OperatorType() == OrderOperatorType.PAY;
}
}
打印如下:
【线程 - main 】订单成功成功:第⼀步,打印⼩票
【线程 - main 】订单成功成功:第⼆步,发送通知商品中⼼添加库存
【线程 - main 】订单成功成功:第四步,奖励业务
【线程 - main 】订单成功成功:第三步,发送⽤户订单⽀付消息
那么,ApplicationEvent对异步⽀持是怎么样的呢?
只要在启动类上加上@EnableAsync,在⽅法体加上@Async
再打印如下:
【线程 - task-1 】订单成功成功:第⼀步,打印⼩票
【线程 - task-2 】订单成功成功:第⼆步,发送通知商品中⼼添加库存
【线程 - task-4 】订单成功成功:第四步,奖励业务
【线程 - task-3 】订单成功成功:第三步,发送⽤户订单⽀付消息
总结
不管是EventObject,还是Observable模型,都是⽤来解耦代码。⾼内聚,低耦合的设计思想⼀⾄到现在都没有被突破过,也是我们在⽇常⼯作过程中时刻要提醒⾃⼰的编码思想。⽽我们更要利⽤好这些前⼈留下的精髓,应⽤到我们实际的业务场景中去。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。