微服务 —— 消息服务中间件 JMS

article/2025/9/22 5:10:25

一、消息服务中间件

对于大多数应用来说,可采用消息服务中间件来提升系统异步通信,消息解耦问题。
消息的作用:异步处理、应用解耦、流量削峰。

异步消息中的两个概念:消息代理、目的地

当消息发送者发送消息,由消息代理接管,消息代理保证消息传送到指定的目的地。

异步消息有两种形式的目的地

1)队列:点对点通信

消息发送者发送消息,消息代理将其放入一个队列中,消息接收者从队列中获取消息内容,消息读取后被移出队列。消息只有唯一的发送者和接受者,但并不是说只能有一个接收者

2) 主题:发布/订阅消息通信

发送者(发布者)发送消息到主题,多个接收者(订阅者)监听(订阅)这个主题,那么就会在消息到达时同时收到消息

两个常见的消息服务规范:

1)JMS(Java Message Service):Java 消息服务。基于 JVM 消息代理规范。ActiveMQ、 HornetMQ 是 JMS 实现。
2) AMQP( Advanced Message Queuing Protocol):高级消息队列协议,也是一个消息代理的规范,兼容 JMS。RabbitMQ 是 AMQP 的实现。
在这里插入图片描述

1、异步处理

在这里插入图片描述

2、应用解耦

在这里插入图片描述

3、流量削峰

在这里插入图片描述

二、JMS 简介

JMS(Java Message Service) 即 Java 消息服务应用程序接口,是一个 Java 平台中关于面向消息中间件(MOM)的 API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。

Java 消息服务是一个与具体平台无关的 API,绝大多数 MOM 提供商都对JMS提供支持。
JMS 是 java 的消息服务,JMS 的客户端之间可以通过 JMS 服务进行异步的消息传输
Java 消息服务为标准消息协议和消息服务提供了一组通用接口,包括创建、发送、读取消息等,用于支持 Java 应用程序开发。
在J2EE中,当两个应用程序使用JMS进行通信时,它们之间并不是直接相连的,而是通过一个共同的消息收发服务连接起来,可以达到解耦的效果

在一些场景下 RPC 的同步方式可能不太适合业务逻辑的处理,并且这种方式在某些场景下会导致业务的紧耦合。基于异步交互模型的 JMS 解决了 RPC 产生的紧耦合问题,它提供了一个可以通过网络访问的抽象消息队列

JMS 接收消息的方式:

(1)同步:使用同步方式接收消息的话,消息订阅者调用 receive() 方法。在receive()中,消息未到达或在到达指定时间之前,方法会阻塞,直到消息可用
(2)异步:使用异步方式接收消息的话,消息订阅者需注册一个消息监听者,类似于事件监听器,只要消息到达,JMS 服务提供者会通过调用监听器的 onMessage() 递送消息

1、JMS 的优势

(1)异步

JMS 天生就是异步的,客户端获取消息的时候,不需要主动发送请求,消息会自动发送给可用的客户端

(2)可靠

JMS 保证消息只会递送一次。大家都遇到过重复创建消息问题,而JMS能帮你避免该问题。

2、消息队列

(1) MQ 消息队列

MQ(Message QueueMQ)消息队列,是一个用于消息的接受和转发的容器,可用于消息的推送。很多人都说 MQ 通过将消息的发送和接收分离,从而来实现应用程序的异步和解偶。这个给人的直觉是——MQ 是异步的,用来解耦的,但是这个只是 MQ 的效果而不是目的。MQ 真正的目的是为了通讯,屏蔽底层复杂的通讯协议,定义了一套应用层的、更加简单的通讯协议
在消息队列中,定义了两个对象——发送数据的叫生产者,接收数据的叫消费者。并且提供了一个 SDK,让我们可以定义自己的生产者和消费者实现消息通讯而无视底层通讯协议。
在这里插入图片描述
● Producer:消息生产者,负责产生和发送消息到 Broker;
● Broker:消息处理中心,负责消息存储、确认、重试等,一般其中会包含多个 queue;
● Consumer:消息消费者,负责从 Broker 中获取消息,并进行相应处理。

(2) MOM 消息中间件

消息队列中间件(MOM:Message Orient MiddleWare),将信息以消息的形式,从一个应用程序传输到另一个或者多个应用程序。

消息队列中间件是分布式系统中重要的组件,主要解决应用耦合,异步消息,流量削锋等问题。实现高性能,高可用,可伸缩和最终一致性架构,是大型分布式系统不可缺少的中间件。
在这里插入图片描述
消息中间件的用途和优点

1️⃣消息异步接受:类似于手机短信的行为,消息发送者不需要等待消息接受者的响应,减少软件多系统集成的耦合度;
2️⃣负责建立网络通信的通道,进行数据的可靠传送,只有接受方接受到消息后才可删除,多个消息也可以组成原子事务;
3️⃣保证数据不重发,不丢失;
4️⃣能够实现跨平台操作,能够为不同操作系统上的软件集成技工数据传送服务;

3、JMS 组成

(1)JMS 体系结构

1)JMS 提供者
连接面向消息中间件的,JMS 接口的一个实现。提供者可以是 Java 平台的 JMS 实现,也可以是非 Java 平台的面向消息中间件的适配器。
2)JMS 客户
生产或消费消息的基于 Java 的应用程序或对象。
3)JMS 生产者
创建并发送消息的 JMS 客户。
4)JMS 消费者
接收消息的 JMS 客户。
5)JMS 消息
包括可以在 JMS 客户之间传递的数据的对象
6)JMS 队列
一个容纳被发送的等待阅读的消息的区域。与队列的 FIFO 不同,,消息的接收顺序并不一定要与消息的发送顺序相同一旦一个消息被阅读,该消息将被从队列中移走
7)JMS主题
一种支持发送消息给多个订阅者的机制。

(2)JMS 消息结构

JMS 消息由三部分组成:
1)消息头
JMS 消息头预定义了若干字段用于客户端与 JMS 提供者之间识别和发送消息,预编译头如下:
在这里插入图片描述
2)消息属性
我们可以给消息设置自定义属性,这些属性主要是提供给应用程序的。对于实现消息过滤功能,消息属性非常有用,JMS API定义了一些标准属性,JMS服务提供者可以选择性的提供部分标准属性。

3)消息体
在消息体中,JMS API定义了五种类型的消息格式,让我们可以以不同的形式发送和接受消息,并提供了对已有消息格式的兼容。不同的消息类型如下:

● Text message:javax.jms.TextMessage,表示一个文本对象。
● Object message:javax.jms.ObjectMessage,表示一个可序列化的 Java 对象。
● Bytes message:javax.jms.BytesMessage,表示字节流数据。
● Stream message:javax.jms.StreamMessage,表示 Java 原始值数据流。
● Map message:javax.jms.MapMessage,表示属性集合的键值对。

(3)消息传输模型

(1)点对点消息传送模型
在点对点消息传送模型中,应用程序由消息队列,发送者,接收者组成。每一个消息发送给一个特殊的消息队列,该队列保存了所有发送给它的消息(除了被接收者消费掉的和过期的消息)。点对点消息模型有一些特性,如下:

● 每个消息只有一个接收者;
● 消息发送者和接收者并没有时间依赖性;
● 当消息发送者发送消息的时候,无论接收者程序在不在运行,都能获取到消息;
● 当接收者收到消息的时候,会发送确认收到通知(acknowledgement)。

在这里插入图片描述
(2)发布/订阅消息传递模型
在发布/订阅消息模型中,发布者发布一个消息,该消息通过 topic 传递给所有的客户端。在这种模型中,发布者和订阅者彼此不知道对方,是匿名的且可以动态发布和订阅topic。topic主要用于保存和传递消息,且会一直保存消息直到消息被传递给客户端。

发布/订阅消息模型特性如下:

● 一个消息可以传递给多个订阅者
● 发布者和订阅者有时间依赖性,只有当客户端创建订阅后才能接受消息,且订阅者需一直保持活动状态以接收消息。

为了缓和这样严格的时间相关性,JMS 允许订阅者创建一个可持久化的订阅。这样,即使订阅者没有被激活(运行),它也能接收到发布者的消息。
在这里插入图片描述
JMS 的传递方式有以下两种

● 标记为 NON_PERSISTENT 的非持久性消息最多投递一次
● 标记为 PRESISTENT 的持久性消息将使用暂存后再转发的机理投递

如果一个 JMS 服务离线,持久性消息不会丢失,但是等到这个服务恢复联机是才会被传递;采用非持久性消息可能降低内务和需要的存储器,所以默认的消息传递方式是非持久性的,但是这种传递方式只有当你不需要接收所有的消息是才使用。

三、JMS 使用

1、发送、接收消息的基本步骤

(1)发送消息的基本步骤

1)创建连接使用的工厂类 JMS ConnectionFactory ;
2)使用管理对象 JMS ConnectionFactory 建立连接 Connection,并启动
3)使用连接 Connection 建立会话 Session
4)使用会话 Session 和管理对象 Destination 创建消息生产者 MessageSender
5)使用消息生产者 MessageSender 发送消息;

(2)消息接收者从JMS接受消息的步骤

1)创建连接使用的工厂类 JMS ConnectionFactory ;
2)使用管理对象 JMS ConnectionFactory 建立连接Connection,并启动
3)使用连接 Connection 建立会话 Session
4)使用会话 Session 和管理对象 Destination 创建消息接收者 MessageReceiver
5)使用消息接收者 MessageReceiver 接受消息,需要用 setMessageListener 将 MessageListener 接口绑定到 MessageReceiver 消息接收者;必须实现 MessageListener 接口,需要定义 onMessage 事件方法。

2、JMS 编程接口

JMS 应用程序由如下基本模块组成:

1)管理对象(Administered objects):

预先配置的JMS对象,由系统管理员为使用JMS的客户端创建,主要有两个被管理的对象(连接工厂(ConnectionFactory)和目的地(Destination))。这两个管理对象由JMS系统管理员通过使用Application Server管理控制台创建,存储在应用程序服务器的JNDI名字空间或JNDI注册表。

2)连接工厂(Connection Factories)

创建Connection对象的工厂,针对两种不同的jms消息模型,分别有QueueConnectionFactory 和 TopicConnectionFactory 两种。可以通过 JNDI 来查找 ConnectionFactory 对象。客户端使用一个连接工厂对象连接到 JMS 服务提供者,它创建了JMS服务提供者和客户端之间的连接。JMS 客户端(如发送者或接受者)会在 JNDI 名字空间中搜索并获取该连接。使用该连接,客户端能够与目的地通讯,往队列或话题发送/接收消息。

// 使用 JNDI 查找连接工厂对象
Context ctx = new InitialContext();
QueueConnectionFactory queueConnFactory = (QueueConnectionFactory) ctx.lookup ("primaryQCF");
Queue purchaseQueue = (Queue) initialCtx.lookup ("Purchase_Queue");
Queue returnQueue = (Queue) ctx.lookup ("Return_Queue");
// 直接实例化连接工厂
ConnectionFactory connFactory = new com.sun.messaging.ConnectionFactory(); 

3)JMS 连接(Connection)

表示 JMS 客户端和服务器端之间的一个活动的连接,是由客户端通过调用连接工厂的方法建立的

// ConnectionFactory对象,可以使用它来创建一个连接
Connection connection = connectionFactory.createConnection();
// 创建完连接后,需要在程序使用结束后关闭它:
connection.close();

4)JMS会话(Session)

表示 JMS 客户与服务器之间的会话状态。JMS会话建立在 JMS 连接之上,表示客户与服务器之间的一个会话进程。 Session是一个单线程上下文,用于生产和消费消息,可以创建出消息生产者和消息消费者。Session对象实现了Session接口,在创建完连接后,我们可以使用它创建Session。

// 这里面提供了参数两个参数,第一个参数是是否支持事务,第二个是事务的类型
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

5)JMS 目的(Destination)

又称消息队列,是实际的消息源。 目的地指明消息被发送的目的地以及客户端接收消息的来源。JMS使用两种目的地,队列和话题。如下代码指定了一个队列和话题。

// 创建一个队列 Session
QueueSession ses = con.createQueueSession (false,Session.AUTO_ACKNOWLEDGE);  
Queue t = (Queue) ctx.lookup ("myQueue");  // create QueueReceiver  
QueueReceiver receiver = ses.createReceiver(t); 
// 创建一个话题 Session
TopicSession ses = con.createTopicSession (false, Session.AUTO_ACKNOWLEDGE); 
Topic t = (Topic) ctx.lookup ("myTopic");  //create TopicSubscriber  
TopicSubscriber receiver = ses.createSubscriber(t);  

6)JMS 生产者(Message Producer)和消费者(Message Consumer)

消息生产者由 Session 创建,用于往目的地发送消息。生产者实现 MessageProducer 接口,我们可以为目的地、队列或话题创建生产者;

MessageProducer producer = session.createProducer(dest);
MessageProducer producer = session.createProducer(queue);
MessageProducer producer = session.createProducer(topic);// 创建完消息生产者后,可以使用send方法发送消息
producer.send(message);    

消息消费者由Session创建,用于接受目的地发送的消息。消费者实现MessageConsumer接口,,我们可以为目的地、队列或话题创建消费者;

MessageConsumer consumer = session.createConsumer(dest);
MessageConsumer consumer = session.createConsumer(queue);
MessageConsumer consumer = session.createConsumer(topic);

8)JMS 消息监听器

JMS 消息监听器是消息的默认事件处理者,他实现了MessageListener接口,该接口包含一个onMessage方法,在该方法中需要定义消息达到后的具体动作。通过调用setMessageListener方法我们给指定消费者定义了消息监听器。如果注册了消息监听器,一旦消息到达,将自动调用监听器的onMessage方法。

Listener myListener = new Listener();
consumer.setMessageListener(myListener);

在这里插入图片描述

(1)消息的生产

1)连接工厂(Connection Factories)

使用JNDI找到ConnectionFactory对象,或者直接实例化一个ConnectionFactory,最终得到一个QueueConnectionFactory或者TopicConnectionFactory的实例,通过这个实例为生产者创建连接。

// 使用 JNDI 查找连接工厂对象
Context ctx = new InitialContext();
ConnectionFactory cf1 =(ConnectionFactory)ctx.lookup("jms / QueueConnectionFactory");
ConnectionFactory cf2 = (ConnectionFactory) ctx.lookup("/jms/TopicConnectionFactory"); 
// 直接实例化连接工厂
ConnectionFactory connFactory = new com.sun.messaging.ConnectionFactory(); 

3)JMS 连接(Connection)

使用 ConnectionFactory 创建连接 Connection。

// ConnectionFactory对象,可以使用它来创建一个连接
Connection connection = connectionFactory.createConnection();
// 调用结束后调用connection.close()关闭所有已经创建的连接
connection.close();

4)JMS会话(Session)

使用 Connection 对象创建 Session。这些 Session 将一组发送和接收合并到一个原子单元内,并提供事务上下文。

// 这里面提供了参数两个参数,第一个参数是是否支持事务,第二个是事务的类型
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

5)JMS 目的(Destination)

客户端使用Destination对象来指定它消费的消息的来源或者它生产的消息的目标。在 point to point 消息传递中,Destination 为 Queue,在消息传递的发布/订阅模型中,为 Topic。

// // 使用 JNDI 查找 Destination 对象
Destination dest = (Queue) ctx.lookup("jms/SomeQueue"); 
// 直接实例化
Queue q = new com.sun.messaging.Queue("world"); 

6)JMS 生产者(Message Producer)

通过 Session 和 Destination 创建 MessageProducer,MessageProducer 用来发送消息。下面的代码中没有说明 Destination 的使用,但是每一个消息必须指定 Destination。

MessageProducer producer = session.createProducer(SomeQueue OR SomeTopic); // 创建完消息生产者后,可以使用 send 方法发送消息
producer.send(message);    

(2)消息的消费

连接工厂、连接、会话和 Destination 对象同消息的生产。
消息的消费分为同步消费和异步消费两种。
1)同步消费

如果是点对点模式的消费者,通过 Session 和 Destination 创建 MessageConsumer,然后用 MessageProducer 的 receive() 方法来接收消息。

MessageConsumer consumer = session.createConsumer(SomeQueue); 

如果是发布/订阅模式的消费者,可以使用 Session.createDurableSubscriber() 创建一个持久的 topic 订阅者,然后用 receive() 方法来接收消息。

MessageConsumer consumer = session.createDurableSubscriber(topic);  

MessageConsumer 不是主动模式,而是被动模式。在启动连接之前,消息不会传递,必须先启动连接,才能接收消息。

connection.start(); 
// 可传入一个long型参数来指定超时时间,单位是ms 
Message msg = consumer.receive(); 

2)异步消费

如果需要异步通信,需要实例化 MessageListener 并在 MessageConsumer 中注册这个监听器。

MessageListener listener = new MyListener(); 
consumer.setMessageListener(listener); 

为了避免丢失消息,注册监听器后,调用连接的start()方法,当消息开始传递,JMS 会自动调用监听器的 onMessage() 接收消息。


http://chatgpt.dhexx.cn/article/gRdE9IVN.shtml

相关文章

JMS解析(二)——JMS简介

JMS解析(一)——JMS简介_踩踩踩从踩的博客-CSDN博客 前言 本篇文章会紧接着上篇文章未介绍完毕的JMS规范,继续消息接收、事务管理、持久化以及应用的介绍。 消息接收 消息接收分为队列接收和topic消息接收 对于队列的接收基本的consumer…

JMS(Java消息服务)(Activemq简单介绍)

是什么? JMS(java消息服务)是规范,它定义了一些规则,一些接口。具体实现由各种做这个产品的厂家或开源组织来实现。 为什么? 在JMS还没有诞生前,每个企业都会有自己的一套内部消息系统&#…

JMS解析(一)——JMS简介

消息中间件MQ及ActiveMQ介绍_踩踩踩从踩的博客-CSDN博客 前言 上篇文章对消息中间件做了个解析,以及ActiveMQ的安装和基本使用,做了个基本了解,因为如果不了JMS规范,一定是不学不好消息中间件和ActiveMQ,本篇文章会从JMS是什么&…

JMS基本概念

简介 JMS即Java消息服务(Java Message Service)应用程序接口,是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。Java消…

JMS概述

** 一、什么是JMS ** JMS即Java消息服务(Java Message Service)应用程序接口,是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行…

深入浅出JMS(一)——JMS简介

如果手机只能进行实时通话,没有留言和短信功能会怎么样?一个电话打过来,正好没有来得及接上,那么这个电话要传递的信息肯定就收不到了。为什么不能先将信息存下来,当用户需要查看信息的时候再去获得信息呢?伴随着这个疑惑,短息和留言应运而生,无论手机是否开机、是否未…

详解 ROI Align 的基本原理和实现细节

转载至http://blog.leanote.com/post/afanti.denggmail.com/b5f4f526490b 欢迎支持原作者。 ROI Align 是在Mask-RCNN这篇论文里提出的一种区域特征聚集方式, 很好地解决了ROI Pooling操作中两次量化造成的区域不匹配(mis-alignment)的问题。实验显示,在检测测任务…

眼睛ROI区域裁剪

为了用深度方法训练一个睁闭眼模型,这里不需要再提取特征,而是需要用到眼睛的原图,第一步就是把眼睛区域裁剪下来。 本文用的是opencv的检测库shape_predictor_68_face_landmarks.dat,得到68特征点后,根据特征点来裁剪…

目标检测Fast RCNN中的ROI pooling

目标检测的任务可以分为两步:选出所有可能存在物体的候选框、判断候选框中的物体是否为前景或者背景。 但是这可能会产生很多的候选区域,如果把它们都喂入CNN,计算量将特别大,这也是rcnn效率低的原因所在。rcnn对每个候选区域都进…

ROI Pooling原理及实现

目标检测architecture通常可以分为两个阶段: (1)region proposal:给定一张输入image找出objects可能存在的所有位置。这一阶段的输出应该是一系列object可能位置的bounding box。这些通常称之为region proposals或者 regions of …

ROI数据分析

目录 1. 专业术语解读 2. 参考资料 1. 专业术语解读 ROI(Return On Investment)投入产出比ROI 是指通过投资而应返回的价值,即企业从一项投资活动中得到的经济回报,通俗点来说就是我们获得的收益和投入成本的比值。 如下图所示,比较多个渠道的效果,寻找最大的ROI渠道。…

ROIAlign源码详细解析

ROI Align 是在Mask-RCNN这篇论文里提出的一种区域特征聚集方式, 很好地解决了ROI Pooling操作中两次量化造成的区域不匹配(mis-alignment)的问题。 其中ROI Align用的是双线性插值(内插)来实现的,在分析源码前我们先来了解下什么是双线性插值。 插值定义&#xf…

Opencv----ROI设置

1 ROI概念 ROI是region of interest首字母的简写,翻译为感性趣的区域,其对象时图像。 对于图像,其实就是一个二维数组,只不过这个二维数组有点特殊,它有头信息,在头信息里会有描述这个二维数组的大小、图片…

HALCON_C#_交互ROI

GDI知识讲解 GDI英文全称:Graphics Device Interface Plus, GDI是对GDI的扩展。 一. GDI概述 二.Graphics类介绍 Graphics 类封装了很多GDI绘图对象,并将这些对象显示到设备上。创建Graphics对象也被称为创建一个画板,创建画板一共…

OpenCV之图像ROI与ROI操作

python代码: import cv2 as cv import numpy as npsrc cv.imread("./test.png") cv.namedWindow("input", cv.WINDOW_AUTOSIZE) cv.imshow("input", src) h, w src.shape[:2]# 获取ROI cy h//2 cx w//2 roi src[cy-100:cy100,c…

ROI Pooling和ROI Align、ROI Warp解析

文中很多内容来源于其他博客,较为详细,有需要可直接按目录跳选到自己需要的部分。 目录 简单介绍 实验比较 ROI理解 ROI Pooling ROI Pooling理解 ROI Pooling example ROI Pooling局限性 ROI Align理解 双线性插值法 ROI Align的反向传播 R…

RoI Pooling 和 RoI Align

RoI Pooling 和 RoI Align 一、背景和基本概念1.背景2.基本概念 二、RoI Pooling原理1.目的2.步骤(以输出RoI feature大小为225为例)Step1Step2Step3Step4 三、RoI Align原理1.目的2.步骤(以输出RoI feature大小为225为例)step1St…

ROI Pooling解析

ROI Pooling最早由Ross Girshick在2015年的论文fast rcnn中提出,是对ROI(Region of Interest)的Pooling操作,广泛应用于物体检测的研究领域。该操作旨在对输入特征图中不同大小的ROI利用池化方法获得固定大小的输出特征图。 ROI Pooling层的输入&#x…

ROI

栗子&#xff1a; #include<cv.h> #include<highgui.h> using namespace cv; //方法1&#xff0c;假如区域为长方形&#xff0c;使用MAT 构造函数设置区域内的值为255 int main() {Mat imageimread("boldt.jpg");//初始化掩模矩阵Mat mask Mat::zeros(…

OpenCV--0016:图像ROI与ROI操作

文章目录 一、图像ROI1. 概念2. 图像ROI操作2.1 矩形感兴趣区域2.1.1 使用Rect函数2.1.2 使用Range2.1.3 应用实例 2.2 不规则ROI区域2.2.1 通过inRange函数生成mask2.2.2 通过“与”操作提取ROI 一、图像ROI 1. 概念 图像ROI&#xff08;region of interest&#xff09;是指…