目录

1、问题背景

1.1 定义事件

1.2 发送事件

1.3 事件处理

2、观察者模式

2.1 模式的定义与特点

2.2 模式的结构与实现

3、核心源码

3.1 FlscApplicationEvent源码

3.2 FlscApplicationEventListener源码

3.3 BusiTypeEventListener源码

3.4 BusiTypeEventListener示例实现源码

4、总结


1、问题背景

在不使用MQ的背景下,对于应用程序内部,需要模块与模块之间的业务解耦,异步处理。在商城中,在订单完成、支付完成、价格校验完成、商品详情价格校验完成这些场景进行埋点,应用程序内部进行事件触发,然后,针对这些业务事件,我们需要开发自己的业务处理器,事件发触发者与事件处理逻辑进行解耦,提高了系统的可维护性、可扩展性。
    实现事件机制,我们并不需要从头开始,直接在Spring的事件机制基础之上,来实现观察者模式。

1.1 定义事件

让FlscApplicationEvent继承ApplicationEvent来实现事件的定义

1.2 发送事件

利用ApplicationContext来发送事件

1.3 事件处理

让FlscApplicationEventListener实现ApplicationListener接口,进行统一的事件处理。

2、观察者模式

2.1 模式的定义与特点

观察者(Observer)模式的定义:指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式,它是对象行为型模式。

观察者模式是一种对象行为型模式,其主要优点如下。

  1. 降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。符合依赖倒置原则。
  2. 目标与观察者之间建立了一套触发机制。

它的主要缺点如下。

  1. 目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用。
  2. 当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率。

2.2 模式的结构与实现

实现观察者模式时要注意具体目标对象和具体观察者对象之间不能直接调用,否则将使两者之间紧密耦合起来,这违反了面向对象的设计原则。

1. 模式的结构

观察者模式的主要角色如下。

  1. 抽象主题(Subject)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
  2. 具体主题(Concrete Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。
  3. 抽象观察者(Observer)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
  4. 具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。

观察者模式的结构图如图 1 所示。

3、核心源码

3.1 FlscApplicationEvent源码

package cn.vetech.center.cps.flsc.common.event;import org.springframework.context.ApplicationEvent;
import org.springframework.util.Assert;import lombok.Data;
/*** 福利商城 ApplicationEvent* @author LiQiao* @date 2021/10/29*/
@Data
public class FlscApplicationEvent extends ApplicationEvent {private static final long serialVersionUID = 1L;private BusiType busiType;private String busiId;private Object data;private Object returnResult;private FlscApplicationEvent(Object source) {super(source);}public static FlscApplicationEvent newInstance(BusiType busiType, String busiId, Object data) {Assert.notNull(busiType, "busiType不能为Null");Assert.hasText(busiId, "busiId不能为空");Assert.notNull(data, "data不能为Null");FlscApplicationEvent flscApplicationEvent = new FlscApplicationEvent(busiId);flscApplicationEvent.busiType = busiType;flscApplicationEvent.busiId = busiId;flscApplicationEvent.data = data;return flscApplicationEvent;}@SuppressWarnings("unchecked")public static <T> T getData(FlscApplicationEvent flscApplicationEvent, Class<T> dataClass) {Assert.notNull(flscApplicationEvent, "flscApplicationEvent不能为Null");Assert.notNull(dataClass, "dataClass不能为Null");return (T)flscApplicationEvent.data;}@SuppressWarnings("unchecked")public static <T> T getReturnResult(FlscApplicationEvent flscApplicationEvent, Class<T> dataClass) {Assert.notNull(flscApplicationEvent, "flscApplicationEvent不能为Null");Assert.notNull(dataClass, "dataClass不能为Null");return (T)flscApplicationEvent.returnResult;}public enum BusiType {/** 订单完成 */ORDER_FINISHED,/** 支付完成 */PAY_FINISHED,/** 价格校验完成 */PRICE_CHECK_FINISHED,/** 商品详情价格校验完成 */GOODS_DETAIL_CHECK_FINISHED;}
}

3.2 FlscApplicationEventListener源码

package cn.vetech.center.cps.flsc.service.fc.common.listener;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import org.vetech.core.modules.utils.mapper.JsonMapper;import cn.vetech.center.cps.flsc.common.event.FlscApplicationEvent;
import lombok.extern.slf4j.Slf4j;@Slf4j
@Component
class FlscApplicationEventListener implements ApplicationListener<FlscApplicationEvent> {@Autowiredprivate FlscApplicationEventListenerHelper flscApplicationEventListenerHelper;@Overridepublic void onApplicationEvent(FlscApplicationEvent flscApplicationEvent) {log.info("接收事件FlscApplicationEvent:{}", JsonMapper.nonEmptyMapper().toJson(flscApplicationEvent));BusiTypeEventListener busiTypeEventListener =this.flscApplicationEventListenerHelper.queryListener(flscApplicationEvent.getBusiType());if (null == busiTypeEventListener) {log.error("BusiType:{},没有找到相应的BusiTypeEventListener", flscApplicationEvent.getBusiType());return;}log.info("处理本地FlscApplicationEvent:{}", JsonMapper.nonEmptyMapper().toJson(flscApplicationEvent));busiTypeEventListener.handle(flscApplicationEvent);}
}

3.3 BusiTypeEventListener源码

package cn.vetech.center.cps.flsc.service.fc.common.listener;import cn.vetech.center.cps.flsc.common.event.FlscApplicationEvent;/*** 单个业务类型的事件监听接口* @author liqiao* @date 2021/04/10*/
public interface BusiTypeEventListener  {/*** * handle* @author LiQiao* @date 2021年10月29日 下午3:28:46* @param flscApplicationEvent*/public void handle(FlscApplicationEvent flscApplicationEvent);/*** * busiType* @author LiQiao* @date 2021年10月29日 下午3:28:51* @return FlscApplicationEvent*/public FlscApplicationEvent.BusiType busiType();
}

3.4 BusiTypeEventListener示例实现源码

package cn.vetech.center.cps.flsc.service.fc.order.listener;import org.springframework.stereotype.Component;
import org.vetech.core.modules.utils.mapper.JsonMapper;import cn.vetech.center.cps.flsc.common.event.FlscApplicationEvent;
import cn.vetech.center.cps.flsc.common.event.FlscApplicationEvent.BusiType;
import cn.vetech.center.cps.flsc.service.fc.common.listener.BusiTypeEventListener;
import cn.vetech.center.cps.flsc.service.fc.order.entity.OrdOrderEntity;
import lombok.extern.slf4j.Slf4j;/*** 处理订单完成的本地事件* @author liqiao* @date 2021/04/10*/
@Slf4j
@Component
public class OrderFinishedListener implements BusiTypeEventListener{@Overridepublic void handle(FlscApplicationEvent flscApplicationEvent) {log.info("订单完成,事件参数:{}", JsonMapper.nonEmptyMapper().toJson(flscApplicationEvent));log.info("订单完成,事件data:{}", JsonMapper.nonEmptyMapper().toJson(FlscApplicationEvent.getData(flscApplicationEvent, OrdOrderEntity.class)));flscApplicationEvent.setReturnResult("11");}@Overridepublic BusiType busiType() {return BusiType.ORDER_FINISHED;}}

4、总结

在跨进程的场景下,我们用MQ去实现。在进程内部的事件机制,我们使用观察者模式去实现。存在即合理,这种进程内部的事件机制,也是有其存在的必要性。

基于Spring事件模型实现观察者模式的工程实践相关推荐

  1. spring 事件模型_Spring–设计领域模型和服务层

    spring 事件模型 我们将为时间表管理构建应用程序. 因此,让我们首先考虑一些用例和实体. 让我用几个项目符号写它们: 任务由经理分配给员工. 一项任务可以分配给许多员工. 员工将他在某些任务上工 ...

  2. 基于Spring Cloud的微服务架构脚手架实践

    文章目录 1 前言 2 脚手架主要提供哪些功能 3 如何使用该脚手架 3.1 项目统一依赖管理 3.2 集成基础模块功能到自己的项目中 4 基础核心功能模块的使用 4.1 集成缓存管理模块 4.1.1 ...

  3. 机器学习(一):基于Logistic回归模型的分类预测(算法实践)——阿里云天池

    文章目录 前言 一.逻辑回归的介绍和应用 1.1 逻辑回归的应用 二.逻辑回归案例 2.1.引入库 2.2读入数据 2.3.调用函数拟合数据 2.4.设置边界 2.5.预测数据 2.6.预测数据值 总 ...

  4. Spring事件机制详解

    一.前言 说来惭愧,对应Spring事件机制之前只知道实现 ApplicationListener 接口,就可以基于Spring自带的事件做一些事情(如ContextRefreshedEvent),但 ...

  5. 跟着 Guava、Spring 学习如何设计观察者模式

    文章首发在公众号(龙台的技术笔记),之后同步到掘金和个人网站:xiaomage.info 今天讲解一篇行为型设计模式,什么是行为型?行为型主要负责设计 类或对象之间的交互.工作中常用的观察者模式就是一 ...

  6. Spring5源码 - 11 Spring事件监听机制_源码篇

    文章目录 pre 事件监听机制的实现原理[观察者模式] 事件 ApplicationEvent 事件监听者 ApplicationEvent 事件发布者 ApplicationEventMultica ...

  7. 三维地图渲染技术工程实践 高德前端技术专家 GMTC 开讲啦

    关于GMTC GMTC全球大前端技术大会是由InfoQ举办的年度前端技术盛会,主要面向各行业对前端.移动感兴趣的中高端技术人员.6月20日-21日,GMTC将在北京国际会议中心拉开帷幕. 高德地图已经 ...

  8. spring事件驱动模型--观察者模式在spring中的应用

    spring中的事件驱动模型也叫作发布订阅模式,是观察者模式的一个典型的应用,关于观察者模式在之前的博文中总结过,http://www.cnblogs.com/fingerboy/p/5468994. ...

  9. Spring事件的观察者模式

    介绍 观察者模式的本质是"定义对象之间的一对多依赖关系,以便当一个对象改变状态时,其所有依赖关系都会得到通知并自动更新." GoF. 观察者模式是发布/订阅模式的子集,它允许许多观 ...

最新文章

  1. sql 分组统计 面试题
  2. 深度学习(三)之LSTM写诗
  3. mysql查找大小写_mysql查询不区分大小写
  4. python的前端开发_Python开发【前端】:html
  5. harbor 多端口_安装Harbor并修改默认使用的80端口
  6. client mysql 逗号_Mysql-Client编码问题
  7. 转 OUI and OPatch Do Not Recognize JDK/JRE on Windows
  8. 【茶知识】普洱茶四大茶区的区别特点
  9. 修正牛顿法及其matlab实现
  10. [SSL_CHX][2021-8-18]取余
  11. 星星城堡童装加盟雾非雾
  12. 将数字转换成科学计数法
  13. _ctl0_ContentPlaceHolder1 或者 ctl00_ContentPlaceHolder1
  14. 解决tomcat7安装后启动时一闪而退的bug
  15. 测试电梯的测试用例_电梯测试用例
  16. Bosun RabbitMQ数据收集
  17. speedoffice文档Word字体倾斜如何弄正
  18. DTSE Tech Talk丨第2期:1小时深度解读SaaS应用系统设计
  19. 华为手机鸿蒙系统下载,鸿蒙2.0正式版
  20. 11 年艺术生转行,逆袭成蚂蚁金服程序员,出版 TensorFlow 教材!

热门文章

  1. H264编码技术[3]
  2. js 动态加版块进页面
  3. 女朋友没工作没文化不上进,甩都甩不掉,我疯了
  4. matlab模糊自适应pid控制仿真程序,模糊自适应整定PID控制matlab仿真程序(刘金锟-先进PID控制及其MATLAB仿真)...
  5. android控件属性padding
  6. 12~18k的前端面试会问什么?
  7. 消息 ByteBuf 详解
  8. ITBP 是什么职位?
  9. 微信小程序实现长按复制和点击复制
  10. CS61A Homework3