• Java 创建事件Event、事件监听EventListener、事件发布publishEvent


    一、概述

    个人认为,事件机制一般可由:事件源source,事件对象Event,事件监听EventListener,事件发布publishEvent组成
    事件源:引起事件发生的源; User用户信息, Order订单信息等为事件源数据,User登录状态loginStatus引起的事件, Order状态status引起的事件
    事件对象:继承ApplicationEvent,事件对象包含事件源,事件对象也就是要被监听的对象; UserEvent, OrderEvent为事件对象,
    事件监听:监听事件对象,事件对象被发布触发时,事件监听到后执行处理逻辑
    事件发布:触发事件的发生


    发布事件publishEvent后,EventListener监听到进行默认同步处理, 线程被阻塞, 这种同步方式吞吐量小耗时,不利用程序高并发。

    在实际应用过程中,事件发布或事件监听后处理逻辑应该都是异步不阻塞线程。

    publishEvent或EventListener 任意一个加上异步@Async即可(程序启动类必须要添加@EnableAsync)。推荐publishEvent加异步。
    如果publishEven和EventListener过程中都有大量处理数据库或其他耗时的业务,也可以两者同时加上@Async

    .

    举例:
    1.OrderEvent订单事件中,用户进行订单支付,订单支付逻辑处理完,同步返回给用户支付完成的消息,同时发布订单事件,异步处理订单发货逻辑等,这样可以将订单支付和订单发货解耦。
    2.UserEvent用户事件中,用户登录成功后,同步返回给用户登录成功的消息,同时发布用户登录事件,异步处理用户登录后记日志登录日志, 写用户购物车缓存等逻辑

    .

    这种事件驱动机制其实是观察者模式(又称发布订阅)具体实现,事件对象(Event)相当于被观察对象(Subject), 事件监听(EventListener) 相当于观察者(Observer)

    下面是简单的代码实现

    二、创建事件源

    package com.xxxx.model;
    import lombok.Data;
    
    @Data
    public class User {
    
        private Long id;
    
        private String loginStatus;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    package com.xxxx.model;
    import lombok.Data;
    
    @Data
    public class Order {
    
        private Long id;
    
        private Integer status;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    三、创建事件对象

    例如:订单状态事件,用户状态事件, 需要继承ApplicationEvent

    package com.xxxx.event;
    
    import com.xxxx.model.Order;
    import org.springframework.context.ApplicationEvent;
    
    public class OrderEvent extends ApplicationEvent {
    
        private Order order;
    
        public OrderEvent(Order order) {
            //ApplicationEvent 构造函数中必须传入source对象,  官方注释中被定义为最初发生事件的对象
            super(order);
            //方式二
            //super(order.getId());
            order = order;
        }
    
        public Order getOrder(){
            return order;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    package com.xxxx.event;
    
    import com.xxxx.model.User;
    import org.springframework.context.ApplicationEvent;
    
    public class UserEvent extends ApplicationEvent {
    
        private User user;
    
        public UserEvent(User user) {
            super(user);
            user = user;
        }
    
        public User getUser(){
            return user;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    四、事件监听

    方法上添加监听事件的注解@EventListener
    方法的参数为继承ApplicationEvent的事件对象

    package com.xxxx.event;
    
    import com.xxxx.model.Order;
    import com.xxxx.model.User;
    import org.springframework.context.event.EventListener;
    import org.springframework.stereotype.Component;
    
    @Component
    public class EventListenerHandle {
    
        /**
         * EventListener 监听到OrderEvent事件,触发方法
         * @param orderEvent
         */
        @Async
        @EventListener
        public void handle(OrderEvent orderEvent){
            Order order = orderEvent.getOrder();
            //getSource() 取决去构建OrderEvent时的super(source)
            //Object object = orderEvent.getSource();
    
            //处理订单业务
            if(order.getStatus() == 0){
    
            }else (order.getStatus() == 1){
    
            }else {
    
            }
        }
    
        /**
         * EventListener 监听到UserEvent事件,触发方法
         * @param userEvent
         */
        @Async
        @EventListener
        public void handle(UserEvent userEvent){
            User user = userEvent.getUser();
            
            //处理用户业务
            if(user.getLoginStatus() == 0){
    
            }else (user.getLoginStatus() == 1){
    
            }else {
    
            }
        }
    }
    
    • 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
    • 49
    • 50

    五、事件发布

    ApplicationContext应用上下文继承了ApplicationEventPublisher,可以调用发布事件

    package com.xxxx.event;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationEvent;
    import org.springframework.stereotype.Component;
    
    @Component
    public class EventPush {
    
        /**
         * ApplicationContext 继承实现了 ApplicationEventPublisher, 可以直接发布事件
         */
        @Autowired
        private ApplicationContext applicationContext;
    
        @Async
        public void publishEvent(ApplicationEvent event){
            if (event instanceof OrderEvent) {
                applicationContext.publishEvent((OrderEvent) event);
                return;
            } else if(event instanceof UserEvent) {
                applicationContext.publishEvent((UserEvent) event);
                return;
            } else {
                //发布失败
            }
        }
    
        @Async
        public void orderEventPush(OrderEvent event){
            applicationContext.publishEvent(event);
        }
    
        @Async
        public void userEventPush(UserEvent event){
            applicationContext.publishEvent(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

    六、调用

    注入依赖类

    @Autowired
    private EventPush eventPush;
    
    • 1
    • 2

    调用事件发布

    Order order = new Order();
    order.setId(1000L);
    //0: 订单创建成功  1:支付成功  .....
    order.setStatus(1);
    
    User user = new User();
    user.setId(1000L);
    //0: 退出成功  1:登录成功  .....
    user.setLoginStatus(1);
    
    //方式一:
    eventPush.orderEventPush(new OrderEvent(order));
    eventPush.userEventPush(new UserEvent(user));
    
    //方式二:
    eventPush.publishEvent(new OrderEvent(order));
    eventPush.publishEvent(new UserEvent(user));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
  • 相关阅读:
    Eureka 学习笔记(2)加载eureka-server.properties中的配置
    Redis的应用
    rollback-only异常令我对事务有了新的认识
    【python海洋专题十九】找范围的语句进阶版本
    1155:回文三位数
    [apue] 进程环境那些事儿
    element-plus el-button 自定义添加icon的方法
    centos 安装ifconfig等
    CentOS7 网络配置
    翻译prompt
  • 原文地址:https://blog.csdn.net/sinat_16998945/article/details/125561114