使用spring自带的发布订阅机制来实现消息发布订阅

news2024/12/23 23:33:05

背景

公司的项目以前代码里面有存在使用spring自带发布订阅的代码,因此稍微学习一下如何使用,并了解一下这种实现方式的优缺点。

优点

  • 实现方便,代码方面基本只需要定义消息体和消费者,适用于小型应用程序。
  • 不依赖外部中间件,因而不需要复杂的配置、部署。

缺点

  • 无法提供消息持久性,项目一旦重启,消息就会丢失,因而不适合实现延迟队列。
  • 对比消息队列,无法实现复杂的消息过滤、路由过滤。
  • 无法实现跨应用程序的事件通信。不同应用程序之间的事件发布和订阅更为容易。

发布订阅模式的优缺点我就不说了,就说说不同实现方式之间的优缺点。

一、创建消息类

消息类需要继承ApplicationEvent类。因为java调用构造函数的机制就是默认会调用父类的构造函数,而ApplicationEvent类只有一个单参数的构造函数,无法自动调用,每个构造函数都需要显式调用父类的构造函数。也就是super(source);

package org.jeecg.modules.test.testPublic;
import org.springframework.context.ApplicationEvent;
import java.util.Objects;

/**
 * @ClassName: MyEvent
 * @Author: zjc
 * @Date: 2023/8/30 18:22
 * @Description:
 **/
public class MyEvent extends ApplicationEvent {
	private String taskId;
	private Integer sourceType;
	
	public MyEvent(Object source) {
		super(source);
	}
	/**
	 *
	 *  @param source   触发事件的对象,可随便传,不过建议传自己可能用得到的对象。好像在调用放直接this的挺多
	 * @param taskId    任务id,自己定义的事件要处理的内容
	 * @param sourceType    自己定义的源类型,用来在多场景触发情况下区分不同场景的标志
	 * @return: null
	 **/
	public MyEvent(Object source,String taskId,Integer sourceType) {
		super(source);
		this.taskId=taskId;
		this.sourceType=sourceType;
	}

	public String getTaskId() {
		return taskId;
	}

	public void setTaskId(String taskId) {
		this.taskId = taskId;
	}

	public Integer getSourceType() {
		return sourceType;
	}

	public void setSourceType(Integer sourceType) {
		this.sourceType = sourceType;
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) return true;
		if (o == null || getClass() != o.getClass()) return false;
		MyEvent myEvent = (MyEvent) o;
		return Objects.equals(taskId, myEvent.taskId) && Objects.equals(sourceType, myEvent.sourceType);
	}

	@Override
	public int hashCode() {
		return Objects.hash(taskId, sourceType);
	}

	@Override
	public String toString() {
		return "MyEvent{" +
				"taskId='" + taskId + '\'' +
				", sourceType=" + sourceType +
				'}';
	}
}

二、发布消息

发布消息可以直接使用ApplicationContext对象调用publishEvent方法。因为ApplicationContext接口继承了ApplicationEventPublisher接口。注意消息类必须要继承ApplicationEvent类才能作为参数发布消息。

package org.jeecg.modules.test.testPublic;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @ClassName: EventController
 * @Author: 
 * @Date: 2023/8/31 17:53
 * @Description:
 **/
@RestController
@Api("test")
@RequestMapping("/test")
public class EventController {
	@Autowired
	private ApplicationContext applicationContext;
	@ApiOperation("testEvent")
	@GetMapping("/testEvent")
	public void testEvent(){
		MyEvent myEvent=new MyEvent(this,"123456",1);
		applicationContext.publishEvent(myEvent);
	}
	@ApiOperation("testEvent1")
	@GetMapping("/testEvent1")
	public void testEvent1(){
		MyEvent myEvent=new MyEvent(this,"123456",2);
		applicationContext.publishEvent(myEvent);
	}
}

三、监听消息

监听消息类需要实现ApplicationListener接口,并通过泛型传入要监听的消息类,并重写onApplicationEvent方法。spring内的同一个消息可以有多个监听类,一旦监听到消息,监听该消息的全部监听类都会执行。

监听类1:

package org.jeecg.modules.test.testPublic;

import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

/**
 * @ClassName: MyEventListener
 * @Author: 
 * @Date: 2023/8/31 17:50
 * @Description:
 **/
@Component
public class MyEventListener implements ApplicationListener<MyEvent> {
	@Override
	public void onApplicationEvent(MyEvent event) {
		System.out.println("消费者开始消费"+event.toString()+event.getSource().toString());
	}
}

消费者2

package org.jeecg.modules.test.testPublic;

import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

/**
 * @ClassName: MyEventListener
 * @Author: 
 * @Date: 2023/8/31 17:50
 * @Description:
 **/
@Component
public class MyEventListener1 implements ApplicationListener<MyEvent> {
	@Override
	public void onApplicationEvent(MyEvent event) {
		System.out.println("消费者1开始消费"+event.toString()+event.getSource().toString());
	}
}

四、测试

调用testEvent接口

在这里插入图片描述

调用testEvent1接口

在这里插入图片描述

结果均符合预期,可以通过在消息体里面加一个字段来区分消息来着不同的触发场景。
即使没有在结构体加上区分消息来源的标识,也可以用消息一开始传入的源对象来大概定位到是哪一个类里面触发的消息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/957747.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JavaScript设计模式(二)——简单工厂模式、抽象工厂模式、建造者模式

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…

pdfh5在线预览pdf文件

前言 pc浏览器和ios的浏览器都可以直接在线显示pdf文件&#xff0c;但是android浏览器不能在线预览pdf文件&#xff0c;如何预览pdf文件&#xff1f; Github: https://github.com/gjTool/pdfh5 Gitee: https://gitee.com/gjTool/pdfh5 使用pdfh5预览pdf 编写预览页面 <…

Spring Framework 学习笔记1:基础

Spring Framework 学习笔记1&#xff1a;基础 1.简介 1.1.生态和发展史 关于 Spring 的生态和发展史&#xff0c;可以观看这个视频。 1.2.系统架构 关于 Spring 的系统架构&#xff0c;可以观看这个视频。 2.Ioc Spring 的核心概念是 Ioc &#xff08;Inversion Of Cont…

grafana8.3创建告警规则

1. 部署grafana的配置文件修改 因为要采用发送邮件的方式通知告警内容所以&#xff0c;在部署grafana时要先配置好SMTP / Emailing的内容&#xff1a; [smtp]enabled true # 开启smtphost smtp.mxhichina.com:465 #设置邮箱服务器地址user testtest.com #设置邮箱用户pas…

Flink SQL你用了吗?

分析&回答 Flink 1.1.0&#xff1a;第一次引入 SQL 模块&#xff0c;并且提供 TableAPI&#xff0c;当然&#xff0c;这时候的功能还非常有限。Flink 1.3.0&#xff1a;在 Streaming SQL 上支持了 Retractions&#xff0c;显著提高了 Streaming SQL 的易用性&#xff0c;使…

排序之选择排序

文章目录 前言一、直接选择排序1、直接选择排序基本思想2、直接选择排序代码实现3、直接选择排序的效率 二、堆排序1、堆排序2、堆排序的效率 前言 选择排序的基本思想就是每一次从待排序的数据元素中选出最小(或最大)的一个元素&#xff0c;存放在序列的起始位置&#xff0c;…

汇编--int指令

中断信息可以来自CPU的内部和外部&#xff0c; 当CPU的内部有需要处理的事情发生的时候&#xff0c;将产生需要马上处理的中断信息&#xff0c;引发中断过程。在http://t.csdn.cn/jihpG&#xff0c;我们讲解了中断过程和两种内中断的处理。 这一章中&#xff0c; 我们讲解另一种…

freemarker学习+集成springboot+导出word

目录 一 FreeMarker简介 二 集成springboot&#xff0c;实现案例导出 三 常见面试题总结 一 FreeMarker简介 FreeMarker 是一款 模板引擎&#xff1a; 即一种基于模板和要改变的数据&#xff0c; 并用来生成输出文本(HTML网页&#xff0c;电子邮件&#xff0c;配置文件&…

2024河南光伏展|河南储能展|河南国际太阳能光伏储能展览会

2024第四届中国&#xff08;郑州&#xff09;太阳能光伏及储能产业展览会 时间&#xff1a;2024年2月26-28日 地点&#xff1a;郑州.中原国际博览中心 河南国际太阳能光伏及储能产业展览会是一个盛大的行业聚会&#xff0c;旨在展示、交流、合作和创新。这个展览会将会是一个…

MATLAB中residue函数用法

目录 语法 说明 示例 求解具有实根的部分分式展开式 展开具有复数根和同次分子及分母的分式 展开分子次数高于分母次数的分式 residue函数的功能是部分分式展开&#xff08;部分分式分解&#xff09;。 语法 [r,p,k] residue(b,a) [b,a] residue(r,p,k) 说明 [r,p…

echarts饼图点击区块事件

效果图&#xff1a; 代码&#xff1a; let option {color: pieColors,series: [{name: Access From,type: pie,radius: [36%, 56%],avoidLabelOverlap: false,label: {formatter: params > {// console.log(params)return {color${params.dataIndex}|${params.name}(${par…

Scala集合继承体系图

Scala集合简介 1&#xff09; Scala 的集合有三大类&#xff1a;序列 Seq、集Set、映射 Map&#xff0c;所有的集合都扩展自 Iterable特质。 2&#xff09; 对于几乎所有的集合类&#xff0c;Scala 都同时提供了可变和不可变的版本&#xff0c;分别位于以下两个包 不可变集合…

软件确认测试的依据有哪些

确认测试 随着我国软件市场的日益繁荣和软件产品的大量涌现,软件评测的重要性越来越显现出来了。 一、确认测试的作用 1、软件确认测试对保障软件产品质量,开拓国际软件市场,促进软件市场健康发展都将发挥重要作用。 2、确认测试的目的是要表明软件是可以工作的&#xff0c…

【Nacos】2023.9.1 最新Nacos源码启动教程 | 超详细 | 包含踩坑经历和解决办法

在官网下载Nacos源码压缩包&#xff0c;或者使用git克隆到本地&#xff0c;使用IDEA打开项目。 Nacos GitHub地址 修改项目的jdk版本为1.8&#xff0c;修改maven使用的jdk版本也是1.8 打开最外边的pom文件&#xff0c;注释掉代码规范检查的插件&#xff08;nacos源码有些impor…

机器学习——聚类算法一

机器学习——聚类算法一 文章目录 前言一、基于numpy实现聚类二、K-Means聚类2.1. 原理2.2. 代码实现2.3. 局限性 三、层次聚类3.1. 原理3.2. 代码实现 四、DBSCAN算法4.1. 原理4.2. 代码实现 五、区别与相同点1. 区别&#xff1a;2. 相同点&#xff1a; 总结 前言 在机器学习…

springboot+activiti5.0整合(工作流引擎)

概述 springboot整合activiti使用modeler进行流程创建&#xff0c;编辑、部署以及删除实例&#xff08;可运行&#xff09; 详细 1、现在来说一下流程&#xff0c;先建立spring boot项目&#xff0c;导入对应的jar包。 <dependencies><dependency><groupId&…

Java 循环语句解析:从小白到循环达人

如果你正在学习编程&#xff0c;那么循环语句是一个绕不开的重要话题。循环语句让我们能够重复执行一段代码&#xff0c;从而实现各种各样的功能。在本篇博客中&#xff0c;我们将围绕 Java 编程语言中的循环语句展开&#xff0c;从最基础的概念出发&#xff0c;一步步引领你从…

Qt日历控件示例-QCalendarWidget

基本说明 QCalendarWidget介绍&#xff1a; QCalendarWidget 是 Qt 框架中提供的一个日期选择控件,用户可以通过该控件快速选择需要的日期,并且支持显示当前月份的日历。 这里&#xff0c;我们继承了QCalendarWidget&#xff0c;做了一些简单封装和样式调整 1.使用的IDE&…

java_error_in_idea.hprof 文件

在用户目录下的java_error_in_idea.hprof文件(/Users/用户) 大约1.5个G,IDEA的错误日志,可以删除

shiny根据数据的长度设置多个色板

shiny根据数据的长度设置多个色板 library(shiny) library(colourpicker) ui <- fluidPage(# 添加一个选择颜色的下拉菜单uiOutput("color_dropdown") )server <- function(input, output) {# 数据长度data_length <- reactive({length(c("数据1"…