• 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);
        }
    
        @Override
        public String toString() {
            return ToStringBuilder.reflectionToString(this);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    package com.jinyi.event.base;
    
    import org.springframework.context.ApplicationEventPublisher;
    import org.springframework.stereotype.Component;
    
    import javax.annotation.Resource;
    
    @Component
    public class EventBusCenter {
    
        @Resource
        private ApplicationEventPublisher applicationEventPublisher;
    
        public void post(BaseEvent event) {
            applicationEventPublisher.publishEvent(event);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    业务事件里的对象

    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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    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{
        @Getter
        private 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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    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
         */
        @Bean
        public SimpleApplicationEventMulticaster applicationEventMulticaster() {
            SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();
            multicaster.setTaskExecutor(taskExecutor);
            return multicaster;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    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
         */
        @Bean
        public 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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    事件类型枚举包

    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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    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> {
    
      @Override
        default 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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    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
         */
        @Override
        public 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 通用订单状态改变---");
            }
        }
    
        @Override
        public void handleException(Throwable exception) {
            IEventHandler.super.handleException(exception);
        }
    
        @Override
        public boolean support(OrderStatusChangeEvent event) {
            return IEventHandler.super.support(event);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    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> {
    
    
        @Override
        public 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 通用订单状态改变---");
            }
        }
    
        @Override
        public boolean support(OrderStatusChangeEvent event) {
            return IEventHandler.super.support(event);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    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> {
    
    
        @Override
        public 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 通用订单状态改变---");
            }
        }
    
        @Override
        public boolean support(OrderStatusChangeEvent event) {
            return IEventHandler.super.support(event);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    测试入口

    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 {
        @Resource
        private EventBusCenter eventBusCenter;
    
        @GetMapping("/post")
        public void bizPost() {
            OrderStatusChangeDTO changeDTO =new OrderStatusChangeDTO();
            changeDTO.setUserId(1L);
            changeDTO.setOrderNo(100L);
            changeDTO.setOrderStatusChange(OrderTrackTypeEnum.ORDER_PAY);
            //仅触发订单支付 和 其他 通用handle
            OrderStatusChangeEvent event = new OrderPayEvent(this, changeDTO);
            eventBusCenter.post(event);
            //广播订单状态变更时间
    //        OrderStatusChangeEvent event1 = new OrderStatusChangeEvent(this, changeDTO);
    //        eventBusCenter.post(event1);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    项目启动类

    @SpringBootApplication
    public class EventApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(EventApplication.class,args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    test:

    localhost:8080/event/post
    
    • 1

    resp:
    在这里插入图片描述

  • 相关阅读:
    openssl C++研发之pem格式处理详解
    java计算机毕业设计基于springboot人职匹配推荐系统
    Spring MVC ViewNameMethodReturnValueHandler原理解析
    编程时遇到的Python语法问题汇总
    jsPlumb导航器
    ArmV8常用汇编指令2
    界面控件DevExpress WPF Scheduler控件 - 如何实现数据的按需加载?
    vue补充继上一篇
    Redis学习记录------Redis6发布和订阅以及三个新数据类型(五)
    Linux命令:普通账号下启动定时任务而无需输入密码
  • 原文地址:https://blog.csdn.net/huangchong0107/article/details/138090196