1.基于Springboot对SpringEvent初步封装

一:前置知识

Spring Event是Spring框架提供的一种事件机制,用于处理组件之间的通信。在复杂的系统中,模块或组件之间的通信是必不可少的。Spring Event可以用于以下场景:

1.系统间解耦:模块或组件之间通过事件进行通信,而不需要相互依赖。

2.异步处理:通过事件,可以异步处理某些任务,提高系统的处理能力。

3.日志记录:通过监听事件,记录系统的运行情况,如用户登录、数据修改等

注:业务系统一定要先实现优雅关闭服务,才能使用 Spring Event,这个和MQ还是有点区别,Spring Event和 MQ 都属于订阅发布模式的应用,然而 MQ 比 SpringEvent 强大且复杂。MQ 更适合应用之间的解耦、隔离、事件通知。例如订单支付、订单完成、订单履约完成等等事件需要广播出去,通知下游其他微服务, 这种场景更适合使用 MQ 。

然而对于应用内需要订阅发布的场景更适合使用 SpringEvent。两者并不矛盾,MQ 能力更强大,技术方案也更”重“一些。Spring Event 更加小巧适合应用内订阅发布,实现业务逻辑解耦。
像我之前的公司里。订单服务内部使用的是Spring Event 进行订单内部逻辑的异步和解耦。订单服务和其他服务之间使用的是Kafka来进行的解耦合数据通信。

二:基础封装

代码层级接口见下截图
在这里插入图片描述
base包里的对象

package com.jinyi.event.base;import org.apache.commons.lang3.builder.ToStringBuilder;
import org.springframework.context.ApplicationEvent;import java.time.Clock;public class BaseEvent extends ApplicationEvent {public BaseEvent() {super("");}public BaseEvent(Object source) {super(source);}public BaseEvent(Object source, Clock clock) {super(source, clock);}@Overridepublic String toString() {return ToStringBuilder.reflectionToString(this);}
}
package com.jinyi.event.base;import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;import javax.annotation.Resource;@Component
public class EventBusCenter {@Resourceprivate ApplicationEventPublisher applicationEventPublisher;public void post(BaseEvent event) {applicationEventPublisher.publishEvent(event);}
}
package com.jinyi.event.base;import com.jinyi.event.enums.OrderTrackTypeEnum;
import lombok.Data;import java.io.Serializable;@Data
public class OrderStatusChangeDTO implements Serializable {private static final long serialVersionUID = 1L;private Long userId;private Long orderNo;private OrderTrackTypeEnum orderStatusChange;public OrderStatusChangeDTO() {}public OrderStatusChangeDTO(Long orderNo, OrderTrackTypeEnum orderStatusChange) {this();this.orderNo = orderNo;this.orderStatusChange = orderStatusChange;}public OrderStatusChangeDTO(Long userId, Long orderNo, OrderTrackTypeEnum orderStatusChange) {this();this.orderNo = userId;this.orderNo = orderNo;this.orderStatusChange = orderStatusChange;}
}

业务事件里的对象

package com.jinyi.event.bizEvent;import com.jinyi.event.base.OrderStatusChangeDTO;
import com.jinyi.event.enums.OrderTrackTypeEnum;/*** 订单支付事件* @date 2024/4/19 15:55* @desc*/
public class OrderPayEvent extends OrderStatusChangeEvent {public OrderPayEvent(Object source, OrderStatusChangeDTO dto) {super(source, dto);if (null == dto.getOrderStatusChange()) {dto.setOrderStatusChange(defaultStatus());}}private OrderTrackTypeEnum defaultStatus() {return OrderTrackTypeEnum.ORDER_PAY;}
}
package com.jinyi.event.bizEvent;import com.jinyi.event.base.BaseEvent;
import com.jinyi.event.base.OrderStatusChangeDTO;
import lombok.Data;
import lombok.EqualsAndHashCode;/*** 订单变化事件BaseEvent对象 :存放该事件通用的param** @date 2024/4/19 15:46* @desc*/
@Data
@EqualsAndHashCode(callSuper = true)
public class OrderStatusChangeEvent extends BaseEvent {private OrderStatusChangeDTO orderStatusChangeDTO;public OrderStatusChangeEvent(Object source, OrderStatusChangeDTO dto) {super(source);this.orderStatusChangeDTO = dto;}
}
package com.jinyi.event.bizEvent;import com.jinyi.event.base.OrderStatusChangeDTO;
import com.jinyi.event.enums.OrderTrackTypeEnum;/*** @date 2024/4/19 16:02* @desc*/
public class OrderUserCancelEvent extends OrderStatusChangeEvent {public OrderUserCancelEvent(Object source, OrderStatusChangeDTO dto) {super(source, dto);if (null == dto.getOrderStatusChange()) {dto.setOrderStatusChange(defaultStatus());}}private OrderTrackTypeEnum defaultStatus() {return OrderTrackTypeEnum.USER_CANCEL;}
}
package com.jinyi.event.bizEvent;import com.jinyi.event.base.OrderStatusChangeDTO;
import com.jinyi.event.enums.OrderTrackTypeEnum;
import lombok.Getter;/*** 扣减库存事件* @date 2024/4/19 15:55* @desc*/public class StockReduceEvent extends OrderStatusChangeEvent{@Getterprivate final Long goodsId;public StockReduceEvent(Object source, OrderStatusChangeDTO dto, Long goodsId) {super(source, dto);this.goodsId = goodsId;if (null == dto.getOrderStatusChange()) {dto.setOrderStatusChange(defaultStatus());}}private OrderTrackTypeEnum defaultStatus() {return OrderTrackTypeEnum.STOCK_REDUCE;}
}

config配置包里相关信息

package com.jinyi.event.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import javax.annotation.Resource;/*** 实现异步处理事件配置* @date 2024/4/19 15:31* @desc*/
@Configuration
public class EventConfig {@Resource@Qualifier("asyncTaskExecutor")private ThreadPoolTaskExecutor taskExecutor;/*** 默认情况下,事件会被同步发送给所有监听器,这意味着如果监听器耗时较长,则会阻塞后续的监听器和发布线程.* @return*/@Beanpublic SimpleApplicationEventMulticaster applicationEventMulticaster() {SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();multicaster.setTaskExecutor(taskExecutor);return multicaster;}
}
package com.jinyi.event.config;import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.ThreadPoolExecutor;@Configuration
@EnableAsync
public class ExecutorConfig {@Value("${executor.corePoolSize:4}")private Integer corePoolSize;@Value("${executor.queueCapacity:1000}")private Integer queueCapacity;@Value("${executor.maxPoolSize:6}")private Integer maxPoolSize;@Value("${executor.keepAliveSeconds:30}")private Integer keepAliveSeconds;@Value("${executor.threadNamePrefix:async-executor-}")private String threadNamePrefix;/*** 线程池* @return*/@Beanpublic ThreadPoolTaskExecutor asyncTaskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setThreadNamePrefix(threadNamePrefix);executor.setCorePoolSize(corePoolSize);executor.setQueueCapacity(queueCapacity);executor.setMaxPoolSize(maxPoolSize);//线程大于coreSize,多余线程数超过30s则销毁executor.setKeepAliveSeconds(keepAliveSeconds);// 设置拒绝策略,调用当前线程执行executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());executor.initialize();return executor;}
}

事件类型枚举包

package com.jinyi.event.enums;public enum OrderTrackTypeEnum {ORDER_CREATE("order_create", "用户下单"),ORDER_PAY("order_pay", "完成支付"),ORDER_FINISH("order_finish", "订单完成"),USER_CANCEL("user_cancel","用户取消订单"),STOCK_REDUCE("stock_reduce","扣减库存"),;private String operatorType;private String describe;OrderTrackTypeEnum(String operatorType, String describe) {this.operatorType = operatorType;this.describe = describe;}public String getOperatorType() {return operatorType;}public String getDescribe() {return describe;}public static String getDescribeByHandle(String handle) {for (OrderTrackTypeEnum handleEnum : OrderTrackTypeEnum.values()) {if (handleEnum.getOperatorType().equals(handle)) {return handleEnum.getDescribe();}}return null;}
}

handle包

package com.jinyi.event.handle;import com.jinyi.event.base.BaseEvent;
import org.springframework.context.ApplicationListener;/**** event handle 基础类***/
public interface IEventHandler<T extends BaseEvent> extends ApplicationListener<T> {@Overridedefault void onApplicationEvent(T event) {try {if (support(event)) {handle(event);}} catch (Throwable e) {handleException(e);}}/*** 事件处理统一方法* @param event*/void handle(T event);/*** 处理异常(默认不进行异常处理)** @param exception*/default void handleException(Throwable exception) {};/*** 子类重写可自定义事件支持是否开启* @param event* @return*/default boolean support(T event) {return true;}
}
package com.jinyi.event.handle;import com.jinyi.event.base.OrderStatusChangeDTO;
import com.jinyi.event.bizEvent.OrderPayEvent;
import com.jinyi.event.bizEvent.OrderStatusChangeEvent;
import com.jinyi.event.bizEvent.OrderUserCancelEvent;
import com.jinyi.event.enums.OrderTrackTypeEnum;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;/*** 订单支付事件** @author huangchong* @date 2024/4/19 15:55* @desc*/
@Component
public class OrderPayEventHandle implements IEventHandler<OrderStatusChangeEvent> {/*** 订单支付事件处理** @param event*/@Overridepublic void handle(OrderStatusChangeEvent event) {if (event instanceof OrderPayEvent){OrderStatusChangeDTO changeDTO = event.getOrderStatusChangeDTO();OrderTrackTypeEnum orderStatusChange = changeDTO.getOrderStatusChange();System.out.println("Thread:" + Thread.currentThread().getName() + orderStatusChange.getDescribe() + "-----");}else {System.out.println("Thread:" + Thread.currentThread().getName() + "--OrderPayEventHandle 通用订单状态改变---");}}@Overridepublic void handleException(Throwable exception) {IEventHandler.super.handleException(exception);}@Overridepublic boolean support(OrderStatusChangeEvent event) {return IEventHandler.super.support(event);}
}
package com.jinyi.event.handle;import com.jinyi.event.base.OrderStatusChangeDTO;
import com.jinyi.event.bizEvent.OrderPayEvent;
import com.jinyi.event.bizEvent.OrderStatusChangeEvent;
import com.jinyi.event.bizEvent.OrderUserCancelEvent;
import com.jinyi.event.enums.OrderTrackTypeEnum;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;@Component
public class OrderUserCancelEventHandle implements IEventHandler<OrderStatusChangeEvent> {@Overridepublic void handle(OrderStatusChangeEvent event) {if (event instanceof OrderUserCancelEvent){OrderStatusChangeDTO changeDTO = event.getOrderStatusChangeDTO();OrderTrackTypeEnum orderStatusChange = changeDTO.getOrderStatusChange();System.out.println("Thread:" + Thread.currentThread().getName() + orderStatusChange.getDescribe() + "-----");}else {System.out.println("Thread:" + Thread.currentThread().getName() + "--OrderUserCancelEventHandle 通用订单状态改变---");}}@Overridepublic boolean support(OrderStatusChangeEvent event) {return IEventHandler.super.support(event);}
}
package com.jinyi.event.handle;import com.jinyi.event.base.OrderStatusChangeDTO;
import com.jinyi.event.bizEvent.OrderStatusChangeEvent;
import com.jinyi.event.bizEvent.OrderUserCancelEvent;
import com.jinyi.event.bizEvent.StockReduceEvent;
import com.jinyi.event.enums.OrderTrackTypeEnum;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;@Component
public class StockReduceEventHandle implements IEventHandler<OrderStatusChangeEvent> {@Overridepublic void handle(OrderStatusChangeEvent event) {Boolean flag = event instanceof StockReduceEvent;if (flag ) {OrderStatusChangeDTO changeDTO = event.getOrderStatusChangeDTO();OrderTrackTypeEnum orderStatusChange = changeDTO.getOrderStatusChange();StockReduceEvent stockReduceEvent = (StockReduceEvent) event;Long goodsId = stockReduceEvent.getGoodsId();System.out.println("Thread:" + Thread.currentThread().getName() + orderStatusChange.getDescribe() + "-111----");}else {System.out.println("Thread:" + Thread.currentThread().getName() + "--StockReduceEventHandle 通用订单状态改变---");}}@Overridepublic boolean support(OrderStatusChangeEvent event) {return IEventHandler.super.support(event);}
}

测试入口

package com.jinyi.event.send;import com.jinyi.event.base.EventBusCenter;
import com.jinyi.event.base.OrderStatusChangeDTO;
import com.jinyi.event.bizEvent.OrderPayEvent;
import com.jinyi.event.bizEvent.OrderStatusChangeEvent;
import com.jinyi.event.enums.OrderTrackTypeEnum;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;/*** @author huangchong* @date 2024/4/19 16:33* @desc*/
@RestController
@RequestMapping("/event")
public class BizPost {@Resourceprivate EventBusCenter eventBusCenter;@GetMapping("/post")public void bizPost() {OrderStatusChangeDTO changeDTO =new OrderStatusChangeDTO();changeDTO.setUserId(1L);changeDTO.setOrderNo(100L);changeDTO.setOrderStatusChange(OrderTrackTypeEnum.ORDER_PAY);//仅触发订单支付 和 其他 通用handleOrderStatusChangeEvent event = new OrderPayEvent(this, changeDTO);eventBusCenter.post(event);//广播订单状态变更时间
//        OrderStatusChangeEvent event1 = new OrderStatusChangeEvent(this, changeDTO);
//        eventBusCenter.post(event1);}
}

项目启动类

@SpringBootApplication
public class EventApplication {public static void main(String[] args) {SpringApplication.run(EventApplication.class,args);}
}

test:

localhost:8080/event/post

resp:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/1745.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

账号安全基本措施1

一、系统账号清理 1.1 将用户设置为无法登录 useradd -s /sbin/nologin lisi shell类型设置为/sbin/nologin用户将无法使用bash或其他shell来登录系统。 1.2 锁定用户。passwd -l 用户名 正常情况下是可以送普通用户切换到其他普通用户的 当锁定密码后passwd -l lisi就用普…

LeetCode:组合求和III之回溯法

题目 题目链接 找出所有相加之和为 n 的 k 个数的组合&#xff0c;且满足下列条件&#xff1a;只使用数字1到9 每个数字 最多使用一次 返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次&#xff0c;组合可以以任何顺序返回。题目图解 ** ** cpp代码 class …

AI预测体彩排列3第2套算法实战化测试第1弹2024年4月22日第1次测试

从今天开始&#xff0c;开始新一轮的测试&#xff0c;本轮测试&#xff0c;以6码为基础&#xff0c;同步测试杀号情况&#xff0c;争取杀至4-5码。经过计算&#xff0c;假如5码命中&#xff0c;即每期125注&#xff0c;投入250元&#xff0c;十期共计2500元&#xff0c;则命中率…

牛客NC233 加起来和为目标值的组合(四)【中等 DFS C++、Java、Go、PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/7a64b6a6cf2e4e88a0a73af0a967a82b 解法 dfs参考答案C class Solution {public:/*** 代码中的类名、方法名、参数名已经指定&#xff0c;请勿修改&#xff0c;直接返回方法规定的值即可*** param nums int整型…

日本二次元团建国内院线:一周一部,占据36.2%票房

从《你想活出怎样的人生》开始&#xff0c;到《哈尔的移动城堡》结束&#xff0c;日本动画正在占据国内院线的整个4月份档期。 包括《数码宝贝02&#xff1a;最初的召唤》、《间谍过家家 代号&#xff1a;白》多部作品在内&#xff0c;整个国内四月份院线日本动画平均一周上映…

【Linux实践室】Linux高级用户管理实战指南:Linux用户与用户组编辑操作详解

&#x1f308;个人主页&#xff1a;聆风吟_ &#x1f525;系列专栏&#xff1a;Linux实践室、网络奇遇记 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 一. ⛳️任务描述二. ⛳️相关知识2.1 &#x1f514;Linux查看用户属性命令2.1.1 &#x1f47b;…

数据结构PT1——线性表/链表

1&#xff1a;顺序存储实现(数组实现) Data&#xff1a; a1 a2 .....ai ai1 .... an .... typedef struct LNode *List; //指向LNode的指针&#xff0c;这是typedef的&#xff0c;你可以随时声明&#xff0c;而不加typedef只是创建一个 struct LNode{ //结构体成员ElementT…

【前端】掌握按钮的显示与隐藏

目录 一、前言二、实现显示与隐藏的四种方式1、CSS属性控制2、JavaScript控制3、Vue.js响应式控制 三、需求背景四、代码实现1、定义变量2、绑定事件3、监听选中的学生4、返回return 五、整体效果1、没有勾选学生2、已勾选学生 六、设置按钮显示与隐藏的优势利弊1、优势2、劣势…

MySQL慢查询怎么办?需要关注Explain的哪些关键字?

目录 1-引言&#xff1a;什么是慢查询1-1 慢查询定义1-2 为什么排查慢查询 2-核心&#xff1a;慢查询排查2-1 慢查询定位2-2 慢查询解决2-2-1 Explain 排查慢查询2-2-2 Explain 重点关键字 3-总结&#xff1a;慢查询知识点小结 1-引言&#xff1a;什么是慢查询 1-1 慢查询定义…

C# 字面量null对于引用类型变量✓和值类型变量×

编译器让相同的字符串字面量共享堆中的同一内存位置以节约内存。 在C#中&#xff0c;字面量&#xff08;literal&#xff09;是指直接表示固定值的符号&#xff0c;比如数字、字符串或者布尔值。而关键字&#xff08;keyword&#xff09;则是由编程语言定义的具有特殊含义的标…

羊大师解读,春季羊奶VS夏季羊奶

羊大师解读&#xff0c;春季羊奶VS夏季羊奶 夏季的羊奶和春季的羊奶在营养成分上并没有本质的区别&#xff0c;都含有丰富的蛋白质、矿物质和维生素等。然而&#xff0c;由于季节和气候的变化&#xff0c;人们饮用羊奶的需求和效果可能会有所不同。 在夏季&#xff0c;天气炎热…

C语言 | Leetcode C语言题解之第35题搜索插入位置

题目&#xff1a; 题解&#xff1a; int searchInsert(int* nums, int numsSize, int target) {int left 0, right numsSize - 1, ans numsSize;while (left < right) {int mid ((right - left) >> 1) left;if (target < nums[mid]) {ans mid;right mid - …

使用vue3+ts+vite从零开始搭建bolg(二)

二、全局变量 2.1element-ui集成 pnpm i element-plus pnpm i element-plus element-plus/icons-vue main.ts配置文件 import ElementPlus from element-plus import element-plus/dist/index.css //ts-ignore import zhCn from element-plus/dist/locale/zh-cn.mjsapp.use…

浅说深度优先搜索(中)——回溯

写在最前 相信在你们不懈的努力之下&#xff0c;基本的递归一定可以写出来了&#xff0c;那么我们现在就来看看递归的升级版——回溯怎么写吧&#xff01; 简说回溯 递归是一种特别重要的解题策略。大部分题目需要找到最优解&#xff0c;而这个求解过程可能存在一定的规律性…

UE5(基础动作)多人游戏制作蹲伏

1.创建输入操作&#xff0c;IA_Crouch 在输入映射中添加 IA_Crouch,在触发器中创建两个索引&#xff0c;已按下已松开来创建蹲伏输入。 蹲伏操作必须要勾选角色-角色移动-crouch勾选可蹲伏否则你的人物无法真正蹲下。 为蹲伏创建函数&#xff0c;创建布尔来判断是否蹲伏。 通过…

CodeGemma初探

什么是 CodeGemma CodeGemma是一系列强大而轻量级的模型的集合&#xff0c;可以执行各种编码任务&#xff0c;包括填充中间代码补全、代码生成、自然语言理解、数学推理和指令跟随。 版本&#xff1a; instruct&#xff1a;7B, 这个版本专门针对自然语言到代码聊天和指令跟随…

day83 AJAX

1什么是AJAX AJAX语法 AJAX Asynchronous JavaScript and XML 异步js和XML 实现页面某一部份更新&#xff0c;无需服务器转发或重定向 1 $.ajax() 语法: $.ajax( { "url" : "url&qu…

数据库主从复制

一、主从复制概述 1、介绍&#xff1a; 主从复制是指将主数据库的 DDL 和 DML 操作写入到二进制日志中&#xff0c;将二进制日志传送到从库服务器&#xff0c;然后在从库上对这些日志重新执行&#xff08;重做&#xff09;&#xff0c;从而使得从库和主库的数据保持同步。 M…

百面算法工程师 | 分类网络总结

欢迎大家订阅我的专栏一起学习共同进步&#xff0c;主要针对25届应届毕业生 祝大家早日拿到offer&#xff01; lets go http://t.csdnimg.cn/dfcH3 目录 4. 经典分类网络与发展 4.1 AlexNet 4.2 VGGNet 4.3 GoogLeNet Inception 4.4 ResNet 4.5 DenseNet 4.6 MobileN…