1.基于Springboot对SpringEvent初步封装

news/2024/9/24 4:57:58/

一:前置知识

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.ppmy.cn/news/1437143.html

相关文章

阿里云直播推流和播流地址的生成方法PHP

最近在用阿里云的直播SDK在进行直播功能的开发,整体来说磕磕绊绊&#xff0c;因为里面有好多的东西&#xff0c;一时半会的搞不定&#xff0c;但是工期又有期限&#xff0c;所以天天熬夜&#xff0c;程序员真心不容易&#xff0c;废话不多说&#xff0c;今天分享这个主要就是来…

设计模式:接口隔离原则(Interface Segregation Principle,ISP)介绍

接口隔离原则&#xff08;Interface Segregation Principle&#xff0c;ISP&#xff09;是面向对象设计原则之一&#xff0c;它强调一个类不应该依赖于它不需要的接口。接口隔离原则的核心思想是将大的接口拆分成更小的、更具体的接口&#xff0c;客户端应该仅依赖于它们需要使…

Sulley入门教学——简介、安装(Win7、VMware)

1、简介 Sulley 是由 Pedram Amini 和 Aaron Portnoy 开发的开源工具。它以 Python 编写&#xff0c;可以轻松地在不同平台上部署和使用。Sulley 提供了一个灵活且功能强大的框架&#xff0c;允许用户定义协议消息的结构、字段类型、边界条件和模糊测试策略。用户可以使用 Sul…

频裂变加群推广强制分享引流源码

视频裂变加群推广强制分享引流源码&#xff0c;用户达到观看次数后需要分享给好友或者群,好友必须点击推广链接后才会增加观看次数。 引导用户转发QV分享,达到快速裂变引流的效果&#xff01; 视频裂变推广程序&#xff0c;强制分享链接&#xff0c;引导用户转发&#xff0c;…

深入解析实时数仓Doris:介绍、架构剖析、应用场景与数据划分细节

码到三十五 &#xff1a; 个人主页 心中有诗画&#xff0c;指尖舞代码&#xff0c;目光览世界&#xff0c;步履越千山&#xff0c;人间尽值得 ! Doris是一款高性能、开源的实时分析数据仓库&#xff0c;旨在为用户提供毫秒级查询响应、高并发、高可用以及易于扩展的OLAP解决方…

LeetCode53. 最大子数组和

LeetCode53. 最大子数组和 解题思路dp 代码 /* 数组长度n 9,连续的区间 那区间长度为1的区间数量是&#xff0c;9个 区间长度为2的区间数量是8个 区间长度为3的连续的区间数量为7个 .... 区间长度为9的区间数量为1个 */ class Solution { public:int maxSubArray(vector<…

目标检测——3D玩具数据集

在数字化时代&#xff0c;计算机视觉技术取得了长足的进展&#xff0c;其中基于形状的3D物体识别技术更是引起了广泛关注。该技术不仅有助于提升计算机对现实世界物体的感知能力&#xff0c;还在多个领域展现出了广阔的应用前景。本文将探讨基于形状的3D物体识别实验的重要性意…

elementui el-date-picker禁止选择今年、今天、之前、时间范围限制18个月

1、禁止选择今年之前的所有年份 <el-date-pickerv-if"tabsActive 0":clearable"false"v-model"yearValue"change"yearTimeChange"type"year"placeholder"选择年"value-format"yyyy":picker-options…