• Spring的事件机制


    参考文章:https://blog.csdn.net/weixin_46228112/article/details/124644633

    一、事件模式中的几个概念

    • 事件源:事件的触发者
    • 事件:描述发生了什么事情的对象
    • 事件监听器:监听到事件发生的时候,做一些处理

    二、使用事件模式实现用户注册功能

    事件机制中几个重要的类

    1、事件对象
    表示所有事件的父类,内部有个source字段,表示事件源;我们自定义的事件需要继承这个类。

    /**
     * 事件对象
     */
    public abstract class AbstractEvent {
     
        //事件源
        protected Object source;
     
        public AbstractEvent(Object source) {
            this.source = source;
        }
     
        public Object getSource() {
            return source;
        }
     
        public void setSource(Object source) {
            this.source = source;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    2、事件监听器
    我们使用一个接口来表示事件监听器,是个泛型接口,后面的类型E表示当前监听器需要监听的事件类型,此接口中只有一个方法,用来实现处理事件的业务;

    /**
     * 事件监听器
     *
     * @param  当前监听器感兴趣的事件类型
     */
    public interface EventListener<E extends AbstractEvent> {
        /**
         * 此方法负责处理事件
         *
         * @param event 要响应的事件对象
         */
        void onEvent(E event);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    3、事件广播器

    • 负责事件监听器的管理(注册监听器&移除监听器,将事件和监听器关联起来)
    • 负责事件的广播(将事件广播给所有的监听器,对该事件感兴趣的监听器会处理该事件)
    /**
     * 事件广播器:
     * 1.负责事件监听器的管理(注册监听器&移除监听器,将事件和监听器关联起来)
     * 2.负责事件的广播(将事件广播给所有的监听器,对该事件感兴趣的监听器会处理该事件)
     */
    public interface EventMulticaster {
     
        /**
         * 广播事件给所有的监听器,对该事件感兴趣的监听器会处理该事件
         *
         * @param event
         */
        void multicastEvent(AbstractEvent event);
     
        /**
         * 添加一个事件监听器(监听器中包含了监听器中能够处理的事件)
         *
         * @param listener 需要添加监听器
         */
        void addEventListener(EventListener<?> listener);
     
     
        /**
         * 将事件监听器移除
         *
         * @param listener 需要移除的监听器
         */
        void removeEventListener(EventListener<?> listener);
    }
    
    • 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

    事件广播器的默认实现

    /**
     * 事件广播器简单实现
     */
    public class SimpleEventMulticaster implements EventMulticaster {
     
        private Map<Class<?>, List<EventListener>> listenerMap = new ConcurrentHashMap<>();
     
        @Override
        public void multicastEvent(AbstractEvent event) {
            List<EventListener> eventListeners = this.listenerMap.get(event.getClass());
            if (eventListeners != null) {
                for (EventListener eventListener : eventListeners) {
                    eventListener.onEvent(event);
                }
            }
        }
     
        @Override
        public void addEventListener(EventListener<?> listener) {
            Class<?> eventType = this.getEventType(listener);
            List<EventListener> eventListeners = this.listenerMap.get(eventType);
            if (eventListeners == null) {
                eventListeners = new ArrayList<>();
                this.listenerMap.put(eventType, eventListeners);
            }
            eventListeners.add(listener);
        }
     
        @Override
        public void removeEventListener(EventListener<?> listener) {
            Class<?> eventType = this.getEventType(listener);
            List<EventListener> eventListeners = this.listenerMap.get(eventType);
            if (eventListeners != null) {
                eventListeners.remove(listener);
            }
        }
     
        /**
         * 获取事件监听器需要监听的事件类型
         *
         * @param listener
         * @return
         */
        protected Class<?> getEventType(EventListener listener) {
            ParameterizedType parameterizedType = (ParameterizedType) listener.getClass().getGenericInterfaces()[0];
            Type eventType = parameterizedType.getActualTypeArguments()[0];
            return (Class<?>) eventType;
        }
     
    }
    
    • 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

    事件机制实现的一个例子

    某个系统,当用户注册成功时,需要给用户发送邮件 + 优惠券

    上面3个类支撑了整个事件模型,下面我们使用上面三个类来实现注册的功能
    前提:springboot web
    需要实现以下三个类:
    1、自定义事件 - 用户注册成功事件
    继承事件源抽象类

    /**
     * @Description: 用户注册成功事件
     */
    public class UserRegisterSuccessEvent extends AbstractEvent {
    
        private String name;
    
        public UserRegisterSuccessEvent(Object source,String name) {
            super(source);
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    2、实现EventListener接口 - 用户注册成功监听

    /**
     * @author houChen
     * @date 2022/8/24 23:51
     * @Description:
     */
    @Component
    public class SendEmailOnUserRegisterListener implements EventListener<UserRegisterSuccessEvent> {
    
        @Override
        public void onEvent(UserRegisterSuccessEvent event) {
            System.out.println(event.getName()+ "用户注册成功,开始发送邮件");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    3、向spring容器中注入 事件广播器

    @Configuration
    public class config {
    
    
        /**
         * @Description:  将所有的事件监听器注册到事件广播器中
         */
        @Bean
        @Autowired(required = false)
        public EventMulticaster eventMulticaster(List<EventListener> eventListeners) { //@1
            EventMulticaster eventPublisher = new SimpleEventMulticaster();
            if (eventListeners != null) {
                eventListeners.forEach(eventPublisher::addEventListener);
            }
            return eventPublisher;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    controller

    @RestController
    @RequestMapping("/test")
    public class TestController {
    
        @Autowired
        private EventMulticaster eventMulticaster;
    
    
        @GetMapping("/register")
        public void regisUser(@RequestParam("username") String username) {
            System.out.println(username + ":注册成功");
            UserRegisterSuccessEvent userRegisterSuccessEvent = new UserRegisterSuccessEvent(this, username);
            eventMulticaster.multicastEvent(userRegisterSuccessEvent);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    测试:访问接口 http://localhost:8080/test/register?username=houchen
    在这里插入图片描述

    如果注册成功,还需要发送优惠券的话,则 向spring容器中添加一个 注册成功发送优惠券的监听器即可

    /**
     * @author houChen
     * @date 2022/8/24 23:51
     * @Description:
     */
    @Component
    public class SendQuanOnUserRegisterListener implements EventListener<UserRegisterSuccessEvent> {
    
        @Override
        public void onEvent(UserRegisterSuccessEvent event) {
            System.out.println(event.getName()+ "用户注册成功,开始发送优惠券");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    发送上述请求
    在这里插入图片描述

    实际上事件机制采用的就是设计模式中的观察者模式,https://blog.csdn.net/hc1285653662/article/details/125381326

    三、Spring中的事件

    1、定义一个事件继承 ApplicationContextEvent

    public class MyEvent extends ApplicationContextEvent {
    
        private String describe;
    
        public MyEvent(ApplicationContext source,String describe) {
            super(source);
            this.describe = describe;
        }
    
        public String getDescribe() {
            return describe;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2、向spring容器中注册该事件的监听器

    @Component
    public class MyEventListenner {
    
        @EventListener(value = {MyEvent.class})
        public void myEventListenner(MyEvent myEvent) {
            System.out.println("监听到了myEvent事件 ----> desp:" + myEvent.getDescribe());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3、发布事件

     @GetMapping("/test1")
        public void test1() {
            applicationContext.publishEvent(new MyEvent(applicationContext, "hello,我是houchenyayayya!!!"));
        }
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

  • 相关阅读:
    JAVA潮购购物网站计算机毕业设计Mybatis+系统+数据库+调试部署
    使用Fontcreator字体制作软件及字体设计学习
    C++ Reference: Standard C++ Library reference: C Library: cwchar: vfwprintf
    vue2+element 通用表格组件封装
    python作业2
    定位进阶(HTML)
    【LVS】lvs的四种模式的区别是什么?
    关于 打开虚拟机出现“...由VMware产品创建,但该产品与此版VMwareWorkstateion不兼容,因此无法使用” 的解决方法
    408计算机网络知识点简记 (背诵用
    SpringCloud 微服务nacos和eureka
  • 原文地址:https://blog.csdn.net/hc1285653662/article/details/126514252