Spring中ApplicationEventPublisher发布订阅模式的实现

 更新时间:2023年07月25日 11:49:41   作者:小白的救赎  
本文主要介绍了Spring中ApplicationEventPublisher发布订阅模式的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

概念

关于发布订阅这个词,其实不仅仅出现在Spring框架当中,其实在Redis中也有存在(其对应的是convertAndSend()方法),还有在MQ消息队列里也是有的,但这里就主要介绍的是关于Spring框架的ApplicationEventPublisher如何做到消息的发布与订阅。随着现在的业务量和需求量越来越大,其实基本都是分布式微服务集群的使用了,所以基本都是用到Redis与MQ。但是对于单体Spring Boot应用时,用Spring自带的发布订阅就已经绰绰有余了。

需要知道的是发布订阅需要有三个对象:事件事件发布源事件接收源(监听器)

事件

对于事件来说,需要去继承ApplicationEvent。至于为什么需要继承ApplicationEvent就需要研究源码,等我后续看完再回来更新笔记。

public class LogEvent extends ApplicationEvent {
    public LogEvent(Object message) {
        super(message);
    }
}

事件发布源

这个基本上都是业务层的代码,但是作为学习阶段,我将其直接放在控制层。关于如何去发布,就需要用到Spring中的ApplicationEventPublisher。

@Slf4j
@RestController
@RequestMapping("/log")
public class LogController {
    @Autowired
    private ApplicationEventPublisher publisher;
    @GetMapping("/publisher")
    public void log() {
        log.info("进入到log方法,开始发送事件");
        publisher.publishEvent(new LogEvent("log方法生成事件信息"));
        log.info("log方法发送事件完毕");
    }
}

监听器

/**
 * 管理员日志监听器
 */
@Slf4j
@Component
public class AdminListener {
    @EventListener(LogEvent.class)
    public void adminListen(LogEvent logEvent) {
        try {
            log.info("管理员监听到的日志信息为,{}", logEvent);
            Thread.sleep(5000); // 睡眠5s
            log.info("管理员监听完毕");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
/**
 * 用户日志事件监听器
 */
@Slf4j
@Component
public class UserListener {
    @EventListener(LogEvent.class)
    public void userListen(LogEvent logEvent) {
        try {
            log.info("用户监听到的日志信息为,{}", logEvent);
            Thread.sleep(10000); // 睡眠10s
            log.info("用户监听完毕");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

执行结果

从执行结果可以发现管理员线程睡眠了5s后执行完毕才会执行用户的代码块。所以表明是同步执行的。

于是为了将同步执行变为异步执行,又在两个监听器的方法上添加了@Async注解,并且一定要在启动类上添加@EnableAsync注解。再次执行会发现两次的执行结果并不一致。两个监听器是异步执行的。甚至在监听器上放置@Order注解可以实现先后顺序,但这里就不演示了。

源码追踪

这里只进行粗略的源码查看,因为作者功力有限无法解释得完全仔细,以后看懂了再回来更新笔记。可以发现其已经使用了JDK8新特性了。从ApplicationEventPublisher的publisher(Application event)方法就会进入到其子类AbstartApplicationContext中。

protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
        Assert.notNull(event, "Event must not be null");
        Object applicationEvent;
        if (event instanceof ApplicationEvent) {
            applicationEvent = (ApplicationEvent)event;
        } else {
            applicationEvent = new PayloadApplicationEvent(this, event);
            if (eventType == null) {
                eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();
            }
        }
        if (this.earlyApplicationEvents != null) {
            this.earlyApplicationEvents.add(applicationEvent);
        } else {
            // 在这步完成真正的发布订阅 只有监听完才会向下继续执行
            this.getApplicationEventMulticaster().multicastEvent((ApplicationEvent)applicationEvent, eventType);
        }
        if (this.parent != null) {
            if (this.parent instanceof AbstractApplicationContext) {
                ((AbstractApplicationContext)this.parent).publishEvent(event, eventType);
            } else {
                this.parent.publishEvent(event);
            }
        }

到此这篇关于Spring中ApplicationEventPublisher发布订阅模式的实现的文章就介绍到这了,更多相关Spring ApplicationEventPublisher发布订阅模式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot3.3中实现多端口监听的示例代码

    SpringBoot3.3中实现多端口监听的示例代码

    在SpringBoot应用中实现多端口监听,可以让一个应用处理不同类型的HTTP请求或暴露多个服务接口,本文详细讲解了通过配置application.yml文件和编写自定义配置类的方法,实现了对多个端口的监听,感兴趣的可以了解一下
    2024-11-11
  • 浅谈PrintStream和PrintWriter的区别和联系

    浅谈PrintStream和PrintWriter的区别和联系

    这篇文章主要介绍了浅谈PrintStream和PrintWriter的区别和联系,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • 详解Java的MyBatis框架中SQL语句映射部分的编写

    详解Java的MyBatis框架中SQL语句映射部分的编写

    这篇文章主要介绍了Java的MyBatis框架中SQL语句映射部分的编写,文中分为resultMap和增删查改实现两个部分来讲解,需要的朋友可以参考下
    2016-04-04
  • Springboot详解RocketMQ实现广播消息流程

    Springboot详解RocketMQ实现广播消息流程

    RocketMQ作为一款纯java、分布式、队列模型的开源消息中间件,支持事务消息、顺序消息、批量消息、定时消息、消息回溯等,本篇我们了解如何实现广播消息
    2022-06-06
  • Java中final与继承操作实例分析

    Java中final与继承操作实例分析

    这篇文章主要介绍了Java中final与继承操作,结合实例形式分析了Java中使用final阻止继承的相关原理与操作注意事项,需要的朋友可以参考下
    2019-09-09
  • Java二分查找算法与数组处理的应用实例

    Java二分查找算法与数组处理的应用实例

    二分查找法,又叫做折半查找法,它是一种效率较高的查找方法。数组对于每一门编程语言来说都是重要的数据结构之一,当然不同语言对数组的实现及处理也不尽相同。Java 语言中提供的数组是用来存储固定大小的同类型元素
    2022-07-07
  • 使用Spring Boot实现操作数据库的接口的过程

    使用Spring Boot实现操作数据库的接口的过程

    本文给大家分享使用Spring Boot实现操作数据库的接口的过程,包括springboot原理解析及实例代码详解,感兴趣的朋友跟随小编一起看看吧
    2021-07-07
  • Spring MVC URL地址映射的示例代码

    Spring MVC URL地址映射的示例代码

    @RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。,这篇文章主要介绍了Spring MVC URL地址映射,需要的朋友可以参考下
    2022-07-07
  • Java实现产生随机字符串主键的UUID工具类

    Java实现产生随机字符串主键的UUID工具类

    这篇文章主要介绍了Java实现产生随机字符串主键的UUID工具类,涉及java随机数与字符串遍历、转换等相关操作技巧,需要的朋友可以参考下
    2017-10-10
  • 利用maven deploy上传本地jar至私服的方法

    利用maven deploy上传本地jar至私服的方法

    这篇文章主要介绍了利用maven deploy上传本地jar至私服的方法,本文结合实例代码给大家介绍的非常详细,需要的朋友可以参考下
    2023-02-02

最新评论