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.hqwc.cn/news/640783.html

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

相关文章

.gitignore语法及配置问题

语法及配置 前言.gitignore语法Git 忽略规则优先级gitignore规则不生效Java项目中常用的.gitignore文件c项目中常用的.gitignore注意事项 前言 在工程中&#xff0c;并不是所有文件都需要保存到版本库中&#xff0c;例如“target”目录及目录下的文件就可以忽略。在Git工作区的…

NLP大模型的训练

NLP模型的训练主要分成两步&#xff1a; 1.先进行通用任务的训练&#xff1b;无监督的样本是无穷无尽的&#xff1b; 这里列举两种&#xff1a;MLM和NSP,NSP由于在某些论文中被证明是无效的&#xff0c;所以用的少&#xff1b; MLM: 接下来会在特定任务上进行finetune>su…

夜神、雷电、android studio手机模拟器资源占用情况

夜神、雷电、android studio手机模拟器内存资源占用情况 由于开发电脑只有16G内存&#xff0c;出于开发需要和本身硬件资源的限制&#xff0c;对多个手机模拟器进行了机器资源占用&#xff08;主要是内存&#xff09;的简单比较。 比较的模拟器包括&#xff1a; 1. Android S…

[Kotlin]引导页

使用Kotlin Jetpack Compose创建一个左右滑动的引导页, 效果如图. 1.添加依赖项 androidx.compose.ui最新版本查询:https://maven.google.com/web/index.html com.google.accompanist:accompanist-pager最新版本查询:https://central.sonatype.com/ 确保在 build.gradle (M…

C语言——内存函数的实现与模拟

1. memcpy 函数 与strcpy 函数类似 1.头文件 <string.h> 2.基本格式 • 函数memcpy从source的位置开始向后复制num个 字节 的数据到destination指向的内存位置。 • 这个函数在遇到 \0 的时候并不会停下来。 • 如果source和destination有任何的重叠&#xff0…

数据分析_数据分析思维(1)

数据分析_数据分析思维(1) 这篇文章具体的给大家介绍数据分析中最为核心的技术之一: 数据分析思维的相关内容。 一、数据分析的三种核心思维 作为新手数据分析师或数据运营, 在面对数据异常的时候, 好多小伙伴都会出现: “好像是A引起的”, “好像也和B渠道有关”, “也可能…

3D MINS 多模态影像导航系统

3D MINS多模态影像导航系统&#xff08;Multimodal Image Navigation System&#xff09;是SunyaTech研发的建立在DICOM&#xff08;Digital Imaging and Communications in Medicine&#xff09;图像基础之上的多模态影像导航系统&#xff0c;集二维影像PACS管理、三维影像层级…

李宏毅2022机器学习/深度学习 个人笔记(3)

本系列用于推导、记录该系列视频中本人不熟悉、或认为有价值的知识点 本篇记录代码效果不佳时应该怎么做 如下图所示&#xff1a; 接下来探讨&#xff0c;当optimization不佳的时候&#xff0c;如何判断是遇到了鞍点还是遇到了局部最小值点&#xff1f;可以通过多元函数的泰勒…

Redis - Redisson tryLock 函数参数分析

这里有三个参数&#xff1a; waitTime&#xff1a;等待时间leaseTime&#xff1a;超时施放时间TimeUnit&#xff1a;时间单位 等待时间 如果 ABC… 多个线程去抢夺一把锁&#xff0c;A 成功了&#xff0c;如果设置的是 -1&#xff0c;那么 BCD... 就不等待&#xff0c;直接返…

高通发布电脑CPU,比英特尔Ultra9领先51%

要说2024年最热门的关键词&#xff0c;那肯定非 AI 莫属&#xff0c;当前 AI 已经开始深入各行各业&#xff0c;AI 电视、AI 手机、AI 车机、AI 家电&#xff0c;以及 AI PC ,这些都意味着 AI 将对各个行业带来的新风向和不小的冲击。 2024 年了&#xff0c;PC 处理器还能卷出什…

验证线缆(汽车线束、网线、多芯线)破损或断开与正常线缆的区别在哪里?依AEM CV-100 k50测试仪

工厂产线生产的线缆&#xff08;汽车线束、网线、多芯线&#xff09;做成成品&#xff0c;即2端都安装好了模块。在这种情况下如何快速的判定此条线缆是合格的呢&#xff0c;此处的合格为物理层面上的合格&#xff08;不会出现开路、短路&#xff09;&#xff0c;也就是最基本保…

第66天:API攻防-接口安全阿里云KEYPostmanDVWSXXE鉴权泄漏

案例一&#xff1a;安全问题-Dvws泄漏&鉴权&XXE 靶场地址&#xff1a;https://github.com/snoopysecurity/dvws-node 利用docker命令去启动 首先先注册一个账户 注册后登录点击admin area 发现点不进去 这里把bp打开但是不抓包&#xff0c;只做流量转发&#xff0c;进…