作者:jini 来源:www.javaresearch.org
Java消息发送服务(Java Messaging Service,JMS)是提供商无关的一套API,用于在程序间进行可靠的消息发送。在客户端-服务器计算中,客户端程序与服务器与服务器建立联系并请求服务。相反,消息发送应用在相互协作的程序之间发送消息。有些程序(在所谓的“对等(peer-to-peer)”应用中)则相互之间直接交换信息(JXTA使用的就是这种模型)。
这两种类型的连网方式如下图所示:
JMS提供了一个中间件消息代理(message broker),后者提供了程序间可靠的、事务性的消息发送。
下面的图演示了点到点的消息发送,这正是本期中要讲到的一种消息发送方式。
虽然这些图中显示的消息提供者和消费者都是物理上的机器,实际上它们也可以是运行在一台或者多台机器上的相互协作的一些进程。
JMS提供者是一个程序,它实现了JMS公共接口中的JMS服务约定。J2EE平台规范要求平台实现包含一个JMS提供者。
大多数人都比较熟悉客户端-服务器模型的消息发送,在这种模型中,客户端程序与服务器建立联系,请求服务、数据,或者同时请求服务和数据。相反,JMS提供了一种更丰富的消息发送模型,这种模型具有以下高级特性:
可靠的消息发送。当消息发送者正在发送消息时,消息接受者无需处于运行状态。而是等等接受者下次做好准备时,再将消息发送到接受者手上。
点到点或者发布/订阅式的消息发送模型。消息的传送可能是一对一的,也可能是一对多的。
事务。消息发送可作为一个分布式事务的一部分。
同步的或异步的消息发送。消息生产者可能会等待接受者的确认,也可能不会。
面向对象的消息发送。JMS允许在客户端之间发送对象,而不是通过使用一些协议来发送结构化的数据。
遗留整合。JMS可以与底层的第三方消息发送系统进行整合。
本期解释了如何使用JMS消息队列来实现两个进程之间简单、可靠的点到点的消息发送。发布/订阅式的消息发送将在后面的期“Enterprise Java Technologies Tech Tips”中讲述。
JMS队列术语
JMS使用消息队列的概念来实现点到点的消息发送。在点到点的消息发送中,总是有一个明确的消息生产者和一个消息消费者。在点到点的消息发送中,与时间没有多大的关系,除非消息发送者为消息定义了一个期限。消息接受这可以接收由消息生产者在过去任何一个时候发送的消息,即使在该消息被编入队列时消息消费者没有处于运行状态。
下面的图显示了一个点到点的消息发送场景。
JMS提供者是一个消息发送服务器,它负责处理消息的持久性、超时、重发、事务回滚以及由JMS提供的其他服务。对于J2EE SDK这种情况,JMS提供者是J2EE服务器程序的一部分。消息生产者发送对象到由JMS维护的一个队列中。消息消费者则从该队列接收消息,并发出确认,表示已经收到消息。
JMS规范定义了一些可用于在进程间发送消息的对象:
JMS管理的对象。有两种JMS管理的对象:目的地和连接工厂。这两种对象都是由系统管理员通过环境管理工具创建的。
目的地。这是一种服务器端的对象,通过这个对象进行消息的发送和接收。JMS队列就是一种目的地对象。
连接工厂。这是一种服务器端的对象,负责配置和创建到一个特定目的地的连接。JMS 队列的JMS连接工厂就是一种QueueConnectionFactory。
连接。这是一种到一个JMS提供者(而不是到一个目的地)的虚拟连接。它被用来创建会话。用于访问队列的一个连接就是一种QueueConnection。
会话。这是一个潜在的消息传送和接收的事务性的工作单元。会话用于创建消息、消息生产者和消息消费者。用于访问队列的一个会话就是一种QueueSession。
消息。这是一种可以从消息目的地发送到消息消费者的对象。消息的类型随要发送的对象类型的不同而不同。例如,为本期提供的示例代码就使用了TextMessage对象。
消息生产者。这是一种由JMS客户端程序使用的、用于发送消息到目的地的对象。JMS客户端程序从一个会话中获取消息生产者对象。程序可以使用QueueSender这种类型的消息生产者对象来发送消息到一个队列中。
消息消费者。这是一种由JMS客户端程序使用的、用于从一个目的地接收消息的对象。JMS客户端程序从一个会话中获取消息接受者对象。程序可以使用QueueReceiver这种类型的消息消费者对象来从一个队列中接收消息。
这里颇有几个新的术语。现在让我们看看如何发送消息。以下步骤展示了从与本期一起提供的示例代码中抽出的一些例子。(想知道如何下载和运行该示例代码,请参考运行示例代码一节。)不过,在运行示例代码之前,你需要配置一下服务器(参见 配置服务器一节)。
发送消息
J2EE参考实现预先配有一个队列连接工厂(名为QueueConnectionFactory)和一个队列(名为jms/Queue)。如果你使用的是JMS服务器,而不是参考实现,或者如果你想试着更改队列连接工厂和/或队列队列的名称,请参考配置服务器一节。
下面是通过一个JMS队列发送消息的步骤。从示例程序TestQueue中抽出的代码片段也穿插在这些步骤中。
通过按名字在JNDI中进行查找,获得一个指向QueueConnectionFactory 的引用:
protected static String qfactoryName =3.
"jms/queue/TechTipsQueueConnectionFactory";4.
...
try {
// 获得JNDI上下文
InitialContext ctx = new InitialContext();
// 获得连接工厂
QueueConnectionFactory qcf =
(QueueConnectionFactory)ctx.lookup(qfactoryName);
2.从 QueueConnectionFactory获得一个QueueConnection,再从这个连接获得一个QueueSession 。按名字在JNDI中查找:
// 获得一个到队列的连接
qc = qcf.createQueueConnection();
//从该连接获得一个会话
QueueSession qs = qc.createQueueSession(
false, Session.AUTO_ACKNOWLEDGE);
// 获得一个队列
Queue q = (Queue)ctx.lookup(queueName);
3. 使用QueueSession创建一个QueueSender,将该队列作为一个参数来传递。(QueueSender是QueueSession与某个特定队列之间的一个关联。):
// 使用这个会话创建一个QueueSender
// and a TextMessage.
QueueSender qsnd = qs.createSender(q);
现在可以用QueueSender来发送消息到队列。
4. 创建一个消息对象(Message的子类),然后使用QueueSender的发送方法将它们发送至目的地。示例程序从Session中获得一个TextMessage对象。接着示例程序将每个程序参数打包到TextMessage 中,然后使用QueueSender将其发送至队列。注意,同一个TextMessage 可以使用多次。
TextMessage tm = qs.createTextMessage();
// 为第一个参数之后的每个参数进行一次循环
// 以文本消息的形式发送参数字符串
for (int i = 2; i < args.length; i++) {
tm.setText(args[i]);
qsnd.send;
}
5.关闭QueueConnection。在try/finally程序块的最后一条语句中关闭连接是一个好习惯。这一步很重要:忘记关闭 QueueConnections 将可能导致服务器上的资源泄漏:
} finally {
if (qc != null) {
qc.close();
}
}
要发送消息到一个消息队列,可以使用TestQueue程序(在缺省的包中),加上一个参数“send”,例如:
$ java TestQueue send jms/queue/MyTestQueue a b c d
Java Message Service 1.0.2 Reference
Implementation (build b14)
Sent: 'a'
Sent: 'b'
Sent: 'c'
Sent: 'd'
接收消息
TestQueue程序按照以下步骤接收消息:
和2从一个消息队列接收消息的起先两步与发送消息是一样的:先是查找连接工厂,再获得一个QueueConnection,然后查找Queue。
从QueueSession 获得一个QueueReceiver :
QueueReceiver qrcv = qs.createReceiver(q);
3. 从Queue接收消息。示例程序进入一个循环,在这个循环中从队列获取消息并将它们打印到标准输出设备。
qc.start();
Message m = qrcv.receive(10000);
while (m != null) {
if (m instanceof TextMessage) {
TextMessage tm = (TextMessage)m;
System.out.println("Received text: '" +
tm.getText() + "'");
} else {
System.out.println("Received a " +
m.getClass().getName());
}
m = qrcv.receive(100);
} finally {
if (qc != null) {
qc.close();
}
}
对QueueConnection的启动方法的调用将告诉连接开始接收消息。QueueReceiver接收方法带有一个参数,该参数表明了等待一条消息的毫秒数。如果消息没有在规定时间内到达,该方法将返回null值。直到消息队列在100毫秒的时间内都保持为空,程序才开始读取和打印收到的消息。在try/finally程序块的结尾有一个finally子句,该子句像前面例子中一样地关闭QueueConnection。
要接收消息队列中的消息,可以使用TestQueue程序,再带上一个参数“recy”,例如:
$ java TestQueue recv jms/queue/MyTestQueue
Java Message Service 1.0.2 Reference
Implementation (build b14)
Received text: 'a'
Received text: 'b'
Received text: 'c'
Received text: 'd'
配置服务器
如果你使用的不是参考引用,或者你想更改队列和/或队列连接工厂的名字,你就需要通过使用平台的管理工具配置JMS提供者。队列或者连接工厂被创建之后,便留在服务器中,直到服务器重新启动。有些平台实现可能会为客户端提供扩展API,以便程序化地创建目的地和连接工厂。
用来在J2EE SDK下创建受管理的对象的工具是。要配置服务器,需:
启动应用服务器。
Create a message queue, giving it a JNDI name. (Do this only once.) To create a
new message queue in the J2EE SDK, first decide on a name for your message
queue. It can be convenient for administration purposes to choose a name that
indicates that the queue is used by JMS, for example, jms/MyTestQueue. Then
execute the command:创建一个消息队列,并为它取一个JNDI名。(只做一次。)要用J2EE SDK创建一个新的消息队列,首先需要为消息队列决定一个名字。为了便于管理, 应该选择一个可以表明该队列是JMS使用的队列,例如jms/MyTestQueue。然后执行命令:
j2eeadmin -addJmsDestination <queuename> queue
用消息队列的实际名字替换<queuename> 。
由于连接工厂名QueueConnectionFactory被硬性地放在示例程序中,因此要告诉程序使用一个不同的连接工厂名,就必须修改源代码,并且重新编译。例如,在TestQueue.java中:
// Change this variable's value to change the
// connection factory name
protected static String qfactoryName =
"QueueConnectionFactory"
重新编译之后,使用j2eeadmin(或者你自己的服务器的工具)创建一个connection factory,给它取个JNDI名,如:
j2eeadmin -addJmsFactory jms/MyQueueConnectionFactory
要列出连接工厂,使用:
j2eeadmin -listJmsFactory
要列出目的地,使用:
j2eeadmin -listJmsDestination
对于不是J2EE SDK的平台,可以在该平台上使用J2EE产品的部署工具来创建所需的消息队列和连接工厂。
运行示例代码
下载这些期的示例存档。这个JAR文件包含了示例程序的完整源代码,包括Java程序文件和HTML格式的文件。你可以使用命令jar xvf ttmar2003.jar 将示例jar中的内容解压缩到你的工作目录下。在运行示例程序前,要确保J2EE服务器正在运行。
多次运行示例程序。试着发送一些成批的消息,但是不接收这些消息,检查一下输出的顺序。
这个示例程序为你试着使用JMS队列提供了切入点。探索一下JMS接口使用的API。例如,可以更改一下程序,试着使用三种不同的接收方式。探索一下事务性的消息发送,或者试着发送各种类型的消息对象。JMS有许多特性,熟练使用它可以提高你的应用设计水平。
要得到更多关于JMS的信息,请参考Java Message Service Tutorial。
分享到:
相关推荐
OSB 中 JMS 配置及队列使用说明 OSB(Oracle Service Bus)是一种基于 Java 的集成平台,旨在帮助企业集成不同的应用程序和系统。JMS(Java Message Service)是 Java 平台上的一种消息服务规范,允许 Java 应用...
JMS-java message Service ,消息队列原理介绍,适合activeMQ开发使用
- **订单处理**:当大量订单涌入时,使用JMS队列可以避免系统因处理能力不足而崩溃。订单作为消息放入队列,后台处理系统按照队列顺序逐个处理,保证业务的连续性。 - **日志记录**:分布式系统中的日志收集可以...
### JMS 教程 - 消息队列、消息服务 #### 企业级消息传递与JMS概述 在深入探讨JMS(Java消息服务)之前,我们先来了解下消息服务的基本概念及其在企业级应用中的重要性。企业级消息传递(Enterprise Messaging)是...
1) 本工程主要演示在SPRING BOOT工程中怎样使用JMS集成IBM-MQ及TLQ两种消息中间件产品 2) 使用SPRING BOOT Conditional机制实现了两种产品按需加载,工程会根据配置文件开关动态加载 3) 实现了普通队列消息发送与...
最近,我的一位同事 (Rudy De Busscher) 发布了关于使用 JMS 队列审计 JPA 实体读取的。 读完这篇文章后,我想知道如何使用 Spring 解决它。问题描述我们有一个非常简单的问题:每次 JPA 实体读取发生时,这个...
Java实现的基于JMS(Java Message Service)协议的消息队列中间件是一种用于应用程序间异步通信的重要技术。消息队列允许应用程序将消息发送到队列而不必等待接收方的响应,提高了系统的可扩展性和容错性。JMS是Java...
本文将详细介绍如何在WebLogic中使用JMS来创建Queue(队列)和TOPIC(主题)并进行消息的发送与接收。 ### 一、JMS基本概念 1. **Queue(队列)**:队列是一种点对点的消息传递模型,其中每个消息只会被一个消费者...
总结起来,"JMS之Spring + ActiveMQ实现消息队列"涉及到的关键知识点包括:Spring框架的JMS支持、ActiveMQ的使用、ConnectionFactory的配置、JmsTemplate和MessageListener的实现,以及消息队列在解决系统解耦和异步...
3. **jms规范教程.pdf** - 这是一个关于JMS规范的教程,可能详细讲解了JMS接口、消息类型(如点对点和发布/订阅模型)、消息队列和主题等核心概念,为理解JMS和ActiveMQ的工作原理提供了基础。 综上所述,这个主题...
- 使用Message Processor,如Scheduled Message Forwarding Processor (SMFP),将消息从Message Store取出并发送到JMS队列或主题。 按照以下步骤配置WSO2 ESB: 1. **创建Proxy Service**: 在ESB管理控制台中,...
本教程将围绕"使用JMS操作ActiveMQ"这一主题,详细阐述如何通过JMS与ActiveMQ进行交互,包括创建生产者、消费者以及消息的发送和接收。 首先,我们需要理解JMS的基本概念。在JMS中,消息生产者(Producer)负责创建...
本指南基于点对点模型,其中消息被路由到维护“传入”消息队列的单个使用者。 这种消息传递类型建立在消息队列、发送方和接收方的概念之上。 每条消息都被寻址到一个特定的队列,接收客户端从为保存它们的消息而建立...
6. **JMS队列**:单个消费者接收消息的有序存储区域,遵循先进先出(FIFO)原则。 7. **JMS主题**:支持多播消息,即一个消息可以被多个订阅者接收。 **JMS模型** 1. **点对点模型**(Queue):生产者向特定队列...
WebSphere MQ 提供了可靠的、有恢复能力的应用程序集成,它使用队列和事务性工具帮助保持消息跨网络的完整性。 Spring JMS 模板提供了两个实现,JmsTemplate 类使用 JMS 1.1 API,子类 JmsTemplate102 则使用 JMS ...
使用浏览队列 建造 为了构建JMS浏览器,必须将每个插件lib / libraries.txt中列出的库添加到插件lib文件夹中。 之后,您可以使用以下命令开始构建 bash$ mvn package 这会将Windows和Linux的版本放置在jmsbrowser....
`javax.jms.Topic`, `javax.jms.MessageProducer`, `javax.jms.MessageConsumer`, `javax.jms.ConnectionFactory`等关键接口,以及其他辅助类和异常类,开发者可以使用这些接口来构建基于JMS的应用程序。...
例如,一个繁忙的Web应用可以使用JMS队列来缓存用户的请求,然后在后台处理这些请求,从而提高系统的响应速度和可扩展性。 总的来说,JMS与WebLogic的结合提供了强大的消息传递能力,使得开发者能够构建健壮、灵活...