• SpringEvent的介绍以及实例


    前言

    该文章是我学习使用SpirngEvent的过程,现在只写了SpringEvent的应用,后续会写一篇从源码关注SpringEvent的实现过程。

    SpringEvent的介绍

    SpringEvent在我认为是一个解决业务解耦的办法,运用了观察者模式,用于当一个业务的更改后,需要改变其他业务的状态。例如一个商品的下单,需要修改商品的库存,以及商家的消息发送等等。之前我做这种业务解耦的时候,使用的时消息队列进行解耦,但如果只是为了解耦而整合了消息队列,就有点大了,我认为,可以使用此方式需要满足下面的条件:

    • 当做完业务的时候,不清楚有多少个子业务要进行更改,例如安防设备的报警,初期可能只是发送消息到持有设备的用户,页面显示报警状态,后期或许会涉及到同步到其他平台业务、和其他安防设备产生连锁报警业务等等。

    SpringEvent的应用

    环境配置

    JDK8
    Spring boot 2.6.10

    业务场景

    当电脑启动的时候,电脑的自启程序需要启动,程序的服务也需要启动等等。

    实现

    创建ComputerStartEvent电脑启动事件类

    /**
     * 电脑启动事件类
     */
    public class ComputerStartEvent extends ApplicationEvent {
    
        private ComputerEntity computerEntity;
        public ComputerEntity getComputerEntity() {
            return computerEntity;
        }
    
        public ComputerStartEvent(ComputerEntity source) {
            super(source);
            this.computerEntity=source;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    创建AutoStartupSoftwareListener 自启软件启动监听类

    /**
    *
    * 自启软件启动监听类
    */
    @Component
    public class AutoStartupSoftwareListener implements ApplicationListener {
    
        @Override
        public void onApplicationEvent(ComputerStartEvent event) {
            ComputerEntity computer=event.getComputerEntity();
            System.out.println("电脑"+computer.getName()+"的自启软件正在进行");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    创建ProgramServiceStartupListener 程序服务启动监听类

    /**
     * 程序服务启动监听类
     */
    @Component
    public class ProgramServiceStartupListener implements ApplicationListener {
        @Override
        public void onApplicationEvent(ComputerStartEvent event) {
            ComputerEntity computer=event.getComputerEntity();
            System.out.println("电脑"+computer.getName()+"的程序服务正在启动");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    客户端代码

    poublic class ComputerService {
    
        @Resource
        private ApplicationEventPublisher applicationEventPublisher;
    
    
        public void computerStart() {
    
            ComputerEntity computer=new ComputerEntity();;
            computer.setComputerId("dafdasf");
            computer.setName("电脑A");
            // 电脑启动操作
            System.out.println(computer.getName()+"电脑启动了");
            
            //发布电脑启动事件
            applicationEventPublisher.publishEvent(new ComputerStartEvent(computer));
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    效果

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LZyZUsxx-1659858328571)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/03b2625488424e38bd3809b266f901dc~tplv-k3u1fbpfcp-watermark.image?)]

    异步实现

    目前有两种方式可以实现异步,

    • 一种是使用@EnableAsync和@Async启动异步。
    • 一种是给Springboot的默认实现SimpleAsyncEventMulticaster类中的taskExecutor字段赋值一个线程池。

    一、使用@EnableAsync和@Async启动异步

    下面为了演示异步的效果,自启软件的监听类不使用异步,程序服务的监听类使用异步,然后每个方法打印当前线程的Id。

    AutoStartupSoftwareListener 自启软件启动监听类

    /**
    * 自启软件启动监听类
    */
    @Component
    public class AutoStartupSoftwareListener implements ApplicationListener {
    
        @Override
        public void onApplicationEvent(ComputerStartEvent event) {
            ComputerEntity computer=event.getComputerEntity();
            System.out.println("电脑"+computer.getName()+"的自启软件正在进行");
            //打印线程Id
            System.out.println("AutoStartupSoftwareListener监听线程id:"+Thread.currentThread().getId());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    ProgramServiceStartupListener 程序服务启动监听类

    /**
     * 程序服务启动监听类
     */
    @EnableAsync
    @Component
    public class ProgramServiceStartupListener implements ApplicationListener {
        @Override
        @Async
        public void onApplicationEvent(ComputerStartEvent event) {
            ComputerEntity computer=event.getComputerEntity();
            System.out.println("电脑"+computer.getName()+"的程序服务正在启动");
            //打印线程Id
            System.out.println("ProgramServiceStartupListener监听线程id:"+Thread.currentThread().getId());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    客户端代码

    poublic class ComputerService {
    
        @Resource
        private ApplicationEventPublisher applicationEventPublisher;
    
    
        public void computerStart() {
    
            ComputerEntity computer=new ComputerEntity();;
            computer.setComputerId("dafdasf");
            computer.setName("电脑A");
            // 电脑启动操作
            System.out.println(computer.getName()+"电脑启动了");
            
            //发布电脑启动事件
            applicationEventPublisher.publishEvent(new ComputerStartEvent(computer));
            //打印线程Id
            System.out.println("computerStart方法线程id:"+Thread.currentThread().getId());
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    效果

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K2z7nDvA-1659858328573)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9abd7784e14144b3a122015105eb3dbb~tplv-k3u1fbpfcp-watermark.image?)]
    异步启用成功

    二、给SimpleAsyncEventMulticaster类中的taskExecutor字段赋值线程池

    创建SimpleAsyncEventMulticaster 继承SimpleApplicationEventMulticaster

    //需要指定下beanName
    @Component("applicationEventMulticaster")
    public class SimpleAsyncEventMulticaster extends SimpleApplicationEventMulticaster {
    
        public SimpleAsyncEventMulticaster(){
            ThreadPoolTaskExecutor taskExecutor=new ThreadPoolTaskExecutor();
            taskExecutor.initialize();
            taskExecutor.setCorePoolSize(5);
            taskExecutor.setMaxPoolSize(100);
            taskExecutor.setQueueCapacity(1000);
            taskExecutor.setThreadNamePrefix("test-async");
            setTaskExecutor(taskExecutor);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    效果

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i2f10oEh-1659858328574)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5bb01efec281429380788a4c9d3deb95~tplv-k3u1fbpfcp-watermark.image?)]

    两种异步的区别

    如果给SimpleAsyncEventMulticastertaskExecutor字段赋值线程池,所有监听类的执行都会是异步的,如果想要个别的任务执行是异步的话,需要重写SimpleAsyncEventMulticastermulticastEvent方法,而使用@Async则不会,这也是为啥推荐的都是@Async方式实现异步。

    总结

    本文章介绍了SpringEvent和应用条件以及实例,这里没有写源码的解析,因为比较长,上述内容如果有误人子弟的地方,望在评论区留言。

  • 相关阅读:
    Unity实现设计模式——责任链模式
    MySQL数据库基础 06
    -22 列表渲染
    VR全景图比平面图多了哪些优势,VR全景可以用在哪些领域
    linux下通过wifi连接网络
    面试最常问的问题——被虐了之后,我翻烂了equals源码,总结如下
    react面试题详解
    T1099 第n小的质数(信息学一本通C++)
    实例分割Yolact边缘端部署 (一) 制作自己的数据集
    指尖上的 NFT|在 G2 上评价 Ambire,有机会获得限量版收藏品
  • 原文地址:https://blog.csdn.net/MDZZ666/article/details/126212173