前言

关于事件驱动模型,百度百科在有明确的解释。在JDKUtil包里抽象了事件驱动,有兴趣的朋友可以自行去看下相关类的定义。Spring事件模型ApplicationEvent是基于JDK里的事件模型,废话不多说,直接看Spring是如何定义事件模型,以及在具体业务场景中的应用。

事件

事件就是事件,鼠标点击一下算一个事件,某个按钮被点击了一下算一个点击事件,那么我订单支付了可以认为支付也算一个件事!触发了某个事件...... 等等。

抽象类ApplicationEvent承载着我们要传播的事件或者消息,白话就是说可以把某个对象用ApplicationEvent这个对象来里的Source来引用。

监听者

上面我们定义了事件,那么事件产生的一系列的效应或者是变动,那么都由这些监听者们去实现。点击下鼠标(事件),那么我记录下日志,你弹出个提示框。支付某个订单(事件),我记录下记录,他发送个支付通知...... 等等。

泛型接口ApplicationListener规定了泛型E的上边界为ApplicationEvent,意思很明确,就是给我们自定义事件用的。Spring最大的优点我认为是留给用户发挥的空间很大,就像神秘的海洋一样,它一直有你探索不完的秘密,每一次你去了解它,它都能给你带来新的事物和理解。

实战

文章SpringPlugin-Core在业务中的应用中,我们用SpringPlugin插件的方式去实现了订单的不同操作!而在某个操作里面,我们可能又要发送操作事件的通知,比如:订单支付了后,要通知打印机打印小票、微信公众号提醒支付信息等等。那么我们来实际的操作下。

定义事件源

public class OrderPayedEvent extends ApplicationEvent {

    /**
* 消息体,这里就设定为当前订单对象
*/
private final Order order; public OrderPayedEvent(Object source) {
super(source);
this.order = (Order) source;
} 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) {
return operatorDTO.getOperatorType() == OrderOperatorType.PAY;
}
}

打印如下:

【线程 - main 】订单成功成功:第一步,打印小票
【线程 - main 】订单成功成功:第二步,发送通知商品中心添加库存
【线程 - main 】订单成功成功:第四步,奖励业务
【线程 - main 】订单成功成功:第三步,发送用户订单支付消息

那么,ApplicationEvent对异步支持是怎么样的呢?

只要在启动类上加上@EnableAsync,在方法体加上@Async

再打印如下:

【线程 - task-1 】订单成功成功:第一步,打印小票
【线程 - task-2 】订单成功成功:第二步,发送通知商品中心添加库存
【线程 - task-4 】订单成功成功:第四步,奖励业务
【线程 - task-3 】订单成功成功:第三步,发送用户订单支付消息

总结

不管是EventObject,还是Observable模型,都是用来解耦代码。高内聚,低耦合的设计思想一至到现在都没有被突破过,也是我们在日常工作过程中时刻要提醒自己的编码思想。而我们更要利用好这些前人留下的精髓,应用到我们实际的业务场景中去。

[代码在GitHub](

Spring事件,ApplicationEvent在业务中的应用的更多相关文章

  1. 从spring源码汲取营养:模仿spring事件发布机制,解耦业务代码

    前言 最近在项目中做了一项优化,对业务代码进行解耦.我们部门做的是警用系统,通俗的说,可理解为110报警.一条警情,会先后经过接警员.处警调度员.一线警员,警情是需要记录每一步的日志,是要可追溯的,比 ...

  2. redis整合Spring集群搭建及业务中的使用

    1.redis安装 Redis是c语言开发的. 安装redis需要c语言的编译环境.如果没有gcc需要在线安装.yum install gcc-c++ 安装步骤: 第一步:redis的源码包上传到li ...

  3. spring事件机制

    前置知识补充: 程序里面所谓的“上下文”就是程序的执行环境,打个比方:你就相当于web程序,你的房子就相当于web程序的上下文,你可以在家里放东西,也可以取东西,你的衣食住行都依赖这个房子,这个房子就 ...

  4. Spring事件发布与监听机制

    我是陈皮,一个在互联网 Coding 的 ITer,微信搜索「陈皮的JavaLib」第一时间阅读最新文章,回复[资料],即可获得我精心整理的技术资料,电子书籍,一线大厂面试资料和优秀简历模板. 目录 ...

  5. 淘系工程师讲解的使用Spring特性优雅书写业务代码

    使用Spring特性优雅书写业务代码   大家在日常业务开发工作中相信多多少少遇到过下面这样的几个场景: 当某一个特定事件或动作发生以后,需要执行很多联动动作,如果串行去执行的话太耗时,如果引入消息中 ...

  6. spring发布和接收定制的事件(spring事件传播)

    spring发布和接收定制的事件(spring事件传播) 2012-12-26 20:05 22111人阅读 评论(2) 收藏 举报  分类: 开源技术(如Struts/spring/Hibernat ...

  7. 【Spring】关于Boot应用中集成Spring Security你必须了解的那些事

    Spring Security Spring Security是Spring社区的一个顶级项目,也是Spring Boot官方推荐使用的Security框架.除了常规的Authentication和A ...

  8. Spring事件解析

    首先介绍Spring事件相关类的关系: 其中EventListener与EventObject均是Java SE的范畴,源码如下: package java.util; public interfac ...

  9. 【转】Spring总结以及在面试中的一些问题

    [转]Spring总结以及在面试中的一些问题. 1.谈谈你对spring IOC和DI的理解,它们有什么区别? IoC Inverse of Control 反转控制的概念,就是将原本在程序中手动创建 ...

随机推荐

  1. React Native startReactApplication 方法简析

    在 React Native 启动流程简析 这篇文章里,我们梳理了 RN 的启动流程,最后的 startReactApplication 由于相对复杂且涉及到最终执行前端 js 的流程,我们单独将其提 ...

  2. Linux基于Docker的Redis主从复制、哨兵模式搭建

    本教程基于CentOS7,开始本教程前,请确保您的Linux系统已安装Docker. 1.使用docker下载redis镜像 docker pull redis 安装完成后,使用docker imag ...

  3. VS Code 搭建stm32开发环境

    MCU免费开发环境 一般芯片厂家会提供各种开发IDE方案,通常其中就包括其自家的集成IDE,如: 意法半导体 STM32CubeIDE NXP Codewarrior TI CCS 另外也可以用ecl ...

  4. freemodbus移植、实例及其测试方法

    Modbus简介 参考:Modbus​协议​深入​讲解 https://www.ni.com/zh-cn/innovations/white-papers/14/the-modbus-protocol ...

  5. Robot Framework 面试题

    什么是 RF 基于可扩展关键字驱动的自动化测试框架 什么是可扩展关键字驱动 可扩展意味着可以自己开发,也可以调用第三方的关键字库 关键字驱动意味着测试用例都是围绕着关键字运行的 RF 的原理(框架?) ...

  6. 比年轻更年轻,快看能否接棒B站?

    撰文 |懂懂 编辑 | 秦言 来源:懂懂笔记 背靠超新Z世代,快看能否接棒B站? 国漫什么时候能追上日漫? 国漫作者真能挣到钱吗? 国漫什么时候才能走向世界? 这是中国漫画从业者的"灵魂三问 ...

  7. 我用MRS-ClickHouse构建的用户画像系统,让老板拍手称赞

    摘要:在移动互联网时代,用户数量庞大,标签数量众多,用户标签的数据量巨大.用户画像系统中,对于标签的存储和查询,不同的企业有不同的实现方案.当前主流的实现方案采用ElasticSearch方案.但基于 ...

  8. ysoserial payloads/JRMPClient

    ysoserial payloads/JRMPClient 环境:JDK8u102 payloads/JRMPClient可以配合exploit/JRMPListener模块来使用 1.在自己服务器上 ...

  9. 【转】Gitlab CI & Docker & Dockerfile & Docker-compose的博客文章

    gitlab权限设置 GitLab功能系列报道-标签(Labels) Gitlab CI 使用高级技巧 docker-compose是个好东西,越用越香 基于docker-compose的Gitlab ...

  10. PHP获取目录中的全部内容RecursiveDirectoryIterator

    这次我们来介绍一个SPL库中的目录迭代器,它的作用其实非常简单,从名字就可以看出来,就是获取指定目录下的所有内容.之前我们要遍历目录获取目录及目录下的所有文件一般是需要进行递归遍历的,自己写这个代码说 ...