入门
我应该学习本教程吗?
本教程概述了Java消息服务(JMS),并提供了开发使用它的程序的基础。 JMS由Sun Microsystems开发,旨在为Java程序提供一种访问企业消息传递系统(也称为面向消息的中间件 (MOM))的方式。 MOM通过以间接方式通过中介在应用程序之间提供异步数据传递,从而提供了一种以松散耦合,灵活的方式集成应用程序的机制。
在学习本教程之前,您应该熟悉Java编程和面向对象的编程概念。
要编写本教程中描述的程序,您需要一个编辑环境。 它可以像操作系统编辑器一样基本。 在开发环境中,许多人使用集成开发环境(IDE),因为它具有专门为编写和测试代码而设计的调试器和其他功能。
要编译程序,您需要Java编译器(javac.exe)。 您还将需要javax.jms
包中的JMS类和javax.naming
包中的Java命名和目录接口(JNDI)类。 您可以从Sun: JMS和JNDI下载这些文件。
要执行和测试程序,您需要访问JMS的供应商实现。 大多数Java 2 Enterprise Edition(J2EE)供应商都提供JMS的实现。 请参阅供应商文档以设置JMS运行时和执行程序。
您的某些编程决策将取决于使用的JMS版本(请参阅JMS 1.1中的新增内容:统一域 )。 JMS 1.1版仅支持点对点接口和Pub / sub接口,以实现向后兼容性;如果使用基于JMS 1.1版的提供程序实现进行严格的新开发,则可以安全地跳过本教程中有关这些主题的部分。
企业消息传递系统
Java消息服务由Sun Microsystems开发,旨在为Java程序提供一种访问企业消息传递系统的方法。 在讨论JMS之前,让我们看一下企业消息传递系统。
企业消息传递系统(通常称为面向消息的中间件 (MOM))提供了一种以松耦合,灵活的方式集成应用程序的机制。 它们基于存储和转发在应用程序之间提供异步数据传递; 也就是说,应用程序不直接相互通信,而是与充当中介的MOM通信。
MOM提供了有保证的消息传递(或至少做出了最大的努力),并使应用程序程序员不必了解远程过程调用(RPC)和网络/通信协议的详细信息。
消息传递的灵活性
如下图所示,应用程序A通过MOM的应用程序编程接口(API)发送消息与应用程序B进行通信。
![应用程序A通过通过MOM的应用程序编程接口(API)发送消息来与应用程序B通信。](https://i-blog.csdnimg.cn/blog_migrate/960a7c060b48137033969e766a6cf31e.png)
MOM将消息路由到应用程序B,该应用程序B可以存在于完全不同的计算机上。 MOM处理网络通信。 如果网络连接不可用,MOM将存储该消息,直到连接可用为止,然后将其转发给应用程序B。
灵活性的另一方面是,当应用程序A发送其消息时,应用程序B甚至可能没有执行。 MOM将保留该消息,直到应用程序B开始执行并尝试检索其消息为止。 这也可以防止应用程序A在等待应用程序B接收消息时阻塞。
这种异步通信要求应用程序的设计与当今大多数应用程序的设计有所不同,但是对于与时间无关或并行处理,这可能是非常有用的方法。
松耦合
企业消息传递系统的真正力量在于应用程序的松耦合 。 在上一节的图中,应用程序A发送其指示特定目的地的消息,例如“订单处理”。 今天,应用程序B提供了订单处理功能。
但是,将来,我们可以用不同的订单处理程序替换应用程序B,而应用程序A绝不明智。 它将继续将其消息发送到“订单处理”,并且消息将继续被处理。
同样,我们可以替换应用程序A,只要替换继续发送消息以进行“订单处理”,订单处理程序就不需要知道有新的应用程序发送订单。
发布和订阅
最初,企业消息传递系统是为了实现点对点模型 (PTP)而开发的,在该模型中,由一个应用程序生成的每个消息都被另一个应用程序接收。 近年来,出现了一种新模型,称为发布和订阅 (或pub / sub)。
发布/订阅将PTP模型中的单个目标替换为内容层次结构,即主题 。 发送应用程序会发布其消息,表明该消息表示有关层次结构中某个主题的信息。
希望接收这些消息的应用程序订阅该主题。 订阅包含子主题的层次结构中的主题,使订户可以接收发布到该主题及其子主题的所有消息。
该图说明了发布和订阅模型。
![发布和订阅模型](https://i-blog.csdnimg.cn/blog_migrate/cb8ff86cadb0f37f224d38fdfb0f89fc.png)
多个应用程序可以同时订阅和发布主题的消息,并且这些应用程序彼此之间保持匿名。 MOM充当代理 ,将主题的已发布消息路由到该主题的所有订阅者。
什么是JMS?
Java消息服务规范1.1指出:
JMS是一组接口和关联的语义,用于定义JMS客户端如何访问企业消息传递产品的功能。
在JMS之前,每个MOM供应商都通过专有API提供了对其产品的应用程序访问权限,该API通常以多种语言提供,包括Java语言。 JMS为Java程序通过MOM产品发送和接收消息提供了一种标准的可移植方式。 用JMS编写的程序可以在实现JMS标准的任何MOM上运行。
JMS可移植性的关键是Sun提供JMS API作为一组接口的事实。 提供JMS功能的产品通过提供实现这些接口的提供程序来实现。
作为开发人员,您通过定义一组消息和一组交换这些消息的客户端应用程序来构建JMS应用程序。
JMS目标
为了更好地理解JMS,它有助于了解JMS规范作者设定的目标。
当今市场上有许多企业消息传递产品,并且生产这些产品的多家公司都参与了JMS的开发。
这些现有系统的功能和功能各不相同。 作者知道,如果JMS包含所有现有系统的所有功能,那将太复杂且笨拙。 同样,他们认为不能将自己仅限于所有系统共有的功能。
作者认为,JMS必须包含实现“复杂的企业应用程序”所需的所有功能,这一点很重要。
如规范中所述,JMS的目标是:
- 定义一组通用的消息传递概念和功能。
- 最小化程序员必须学习使用企业消息传递的概念。
- 最大化消息传递应用程序的可移植性。
- 最小化实现提供程序所需的工作。
- 提供点对点域和pub / sub 域的客户端接口。 “域”是前面讨论的消息传递模型的JMS术语。 (注意:提供程序不必同时实现两个域。)
JMS 1.1的新增功能:统一域
在1.1版之前的JMS版本中,每个域都有特定于该域的自己的客户端接口集。 JMS版本1.1提供了一组接口,允许客户端在两个域中发送和接收消息。 这些“独立于域的接口”保留每个域的语义和行为,并且是实现JMS客户端的首选。 支持特定于域的接口以实现向后兼容,不应将其用于新开发。
统一域的好处是:
- 它为客户端编程提供了更简单的编程模型。
- 队列和主题上的操作都可以属于同一事务。
- 它为JMS提供者提供了优化其实现的机会。
JMS不提供的内容
JMS规范未解决MOM产品中常见的以下功能。 尽管JMS作者承认对于开发健壮的消息传递应用程序很重要,但是这些功能被认为是JMS提供程序特定的。
JMS提供者可以随意使用任意方式自由实现这些功能,如果有的话:
- 负载平衡和容错
- 错误和咨询系统消息和通知
- 行政
- 安全
- 有线协议
- 消息类型存储库
JMS概述和体系结构
应用领域
JMS应用程序包含以下元素:
- JMS客户端。 使用JMS API发送和接收消息的Java程序。
- 非JMS客户端。 重要的是要意识到遗留程序通常将成为整个JMS应用程序的一部分,并且必须在计划中预料到它们的存在。
- 讯息。 JMS和非JMS客户端要交换的消息的格式和内容对于JMS应用程序的设计是不可或缺的。
- JMS提供者。 如前所述,JMS定义了一组接口,提供商必须为其提供特定于其MOM产品的具体实现。
- 受管理的对象。 消息传递系统提供程序的管理员创建与提供程序的专有技术隔离的对象。
管理对象
MOM产品的提供者在用于实现消息传递的机制和技术上有很大不同。 为了使JMS客户端具有可移植性,必须将实现JMS接口的对象与提供者的专有技术隔离。
执行此操作的机制是受管理的对象 。 这些实现JMS接口的对象由提供者的消息传递系统的管理员创建,并放置在JNDI名称空间中。
然后,对象将由JMS程序检索,并通过它们实现的JMS接口进行访问。 JMS提供者必须提供一个工具,该工具允许创建管理对象及其在JNDI名称空间中的放置。
有两种类型的管理对象:
-
ConnectionFactory
:用于创建与提供程序的基础消息传递系统的连接。 -
Destination
:JMS客户端使用它来指定发送消息的目的地或接收消息的源。
尽管受管理对象本身是特定于提供者实现的类的实例,但是可以使用可移植机制(JNDI)检索它们,并通过可移植接口(JMS)对其进行访问。 JMS程序只需要知道被管理对象的JNDI名称和JMS接口类型; 不需要特定于提供商的知识。
介面
JMS定义了一组高级接口,这些接口封装了各种消息传递概念。 反过来,将为两个消息传递域(PTP和pub / sub)进一步定义和定制这些接口。
高级接口是:
-
ConnectionFactory
:创建Connection
的管理对象。 -
Connection
:到提供程序的活动连接。 -
Destination
:托管对象,它封装了消息目标的标识,例如消息发送或接收的位置。 -
Session
:用于发送和接收消息的单线程上下文。 为简单起见,由于Session
控制事务,因此限制了多个线程的并发访问。 多个Session
可以用于多线程应用程序。 -
MessageProducer
:用于发送消息。 -
MessageConsumer
:用于接收消息。
接口(续)
下表列出了从每个高级接口继承的特定于域的接口。
高级界面 | PTP域 | 发布/订阅域 |
---|---|---|
ConnectionFactory | QueueConnectionFactory | TopicConnectionFactory |
Connection | QueueConnection | TopicConnection |
Destination | Queue | Topic |
Session | QueueSession | TopicSession |
MessageProducer | QueueSender | TopicPublisher |
MessageConsumer | QueueReceiver , QueueBrowser | TopicSubscriber |
接口:JMS 1.1中的更改
在以前的JMS版本中,高级接口是特定于域的接口的父级,并且仅包含两个域共有的那些功能。 JMS提供程序未提供高级接口的实现。 在JMS 1.1中,高级接口现在被认为是“公共接口”,并且包含两个域的所有功能。 JMS提供程序必须提供这些接口的实现。 尽管公用接口仍然是特定于域的接口的父级,但是它们现在是JMS客户端编程的首选方法,并且仅提供特定于域的接口是为了向后兼容。
下面将重述上一节中的表,其中显示了常用接口。
JMS通用接口 | PTP域 | 发布/订阅域 |
---|---|---|
ConnectionFactory | QueueConnectionFactory | TopicConnectionFactory |
Connection | QueueConnection | TopicConnection |
Destination | Queue | Topic |
Session | QueueSession | TopicSession |
MessageProducer | QueueSender | TopicPublisher |
MessageConsumer | QueueReceiver , QueueBrowser | TopicSubscriber |
使用通用接口统一域会导致某些特定于域的类继承不适合该域的方法。 如果这在客户端代码中发生,则要求JMS提供者抛出IllegalStateException
。
开发JMS程序
一个典型的JMS程序通过以下步骤开始生成和使用消息:
- 通过JNDI查找
ConnectionFactory
。 - 通过JNDI查找一个或多个
Destination
。 - 使用
ConnectionFactory
创建一个Connection
。 - 使用
Connection
创建一个或多个Session
。 - 使用
Session
和Destination
来创建所需的MessageProducer
和MessageConsumer
。 - 启动
Connection
。
此时,消息可以开始流动,并且应用程序可以根据需要接收,处理和发送消息。 在后面的部分中,我们将开发JMS程序,您将详细了解此设置。
留言内容
消息系统的核心当然是消息。 JMS为不同类型的内容提供了几种消息类型,但是所有消息都从Message
接口派生。
Message
分为三个组成部分:
- 标头是一组标准字段,供客户端和提供程序用来标识和路由消息。
- 属性提供了用于向消息中添加可选头字段的功能。 如果您的应用程序需要以标准标头字段未提供的方式对消息进行分类或分类,则可以向消息添加属性以完成该分类或分类。
set<Type>Property(...)
和get<Type>Property(...)
方法来设置和获取各种Java类型的属性,包括Object
。 JMS定义了一组标准的属性,提供者可以选择提供这些属性。 - 该消息的主体中包含待递送到接收应用程序的内容。 每个消息接口都专门针对其支持的内容类型。
标头字段
以下列表给出了Message
的每个标头字段的名称,其对应的Java类型以及对该字段的描述:
-
JMSMessageID
类型string
唯一标识提供者发送的每条消息。 该字段由提供商在发送过程中设置; 客户端在发送消息之前无法确定消息的
JMSMessageID
。 -
JMSDestination
输入Destination
消息发送到的
Destination
; 由提供商在发送过程中设置。 -
JMSDeliveryMode
输入int
包含值
DeliveryMode.PERSISTENT
或DeliveryMode.NON_PERSISTENT
。 持久消息“一次且仅一次”传递; 非持久消息“最多一次”传递。 请注意,“最多一次”包括完全不交付。 在应用程序或系统故障期间,提供程序可能会丢失非持久消息。 将格外小心,以确保持久消息不受故障影响。 发送持久性消息时通常会产生相当大的开销,并且在确定消息的传递模式时必须仔细考虑可靠性和性能之间的折衷。 -
JMSTimestamp
输入long
消息传递给提供者的时间; 由提供商在发送过程中设置。
-
JMSExpiration
输入long
消息应过期的时间。 该值在发送过程中作为发送方法的生存时间值与当前时间之和计算得出。 提供者不应传递过期的消息。 值为0表示该消息不会过期。
-
JMSPriority
输入int
消息的优先级; 由提供商在发送过程中设置。 最低优先级为0。 优先级9是最高优先级。
-
JMSCorrelationID
类型string
通常用于将响应消息与请求消息链接; 由发送消息的JMS程序设置。 响应来自另一个JMS程序的消息的JMS程序会将其响应的消息的
JMSMessageID
复制到此字段中,以便请求程序可以将响应与它所发出的特定请求相关联 。 -
JMSReplyTo
输入Destination
请求程序使用它来指示应将答复消息发送到何处; 由发送消息的JMS程序设置。
-
JMSType
类型string
可以由JMS程序用来指示消息的类型。 一些提供者维护消息类型的存储库,并将使用此字段来引用存储库中的类型定义。 在这种情况下,JMS程序不应使用此字段。
-
JMSRedelivered
输入boolean
指示该消息是较早传递给JMS程序的,但是该程序未确认其接收; 由提供商在接收处理期间设置。
标准特性
下表列出了Message
的每个标准属性的名称,其对应的Java类型以及对该属性的描述。 提供程序对标准属性的支持是可选的。 JMS为这些以及将来的JMS定义的属性保留“ JMSX”属性名称。
-
JMSXUserID
类型string
发送消息的用户的身份。
-
JMSXApplID
类型string
发送消息的应用程序的身份。
-
JMSXDeliveryCount
输入int
尝试传递消息的次数。
-
JMSXGroupID
类型string
该消息所属的消息组的标识。
-
JMSXGroupSeq
输入int
该消息在消息组中的序列号。
-
JMSXProducerTXID
输入string
产生此消息的交易的标识。
-
JMSXConsumerTXID
类型string
使用此消息的事务的标识。
-
JMSXRcvTimestamp
输入long
JMS将消息传递给使用者的时间。
-
JMSXState
输入int
由维护消息的消息仓库的提供者使用; 通常,JMS生产者或消费者不感兴趣。
-
JMSX_<vendor_name>
保留用于提供程序特定的属性。
邮件正文
消息正文有五种形式,每种形式由扩展Message
的接口定义。 这些接口是:
-
StreamMessage
:包含Java基本值流,这些Java基本值使用标准流操作填充并按顺序读取。 -
MapMessage
:包含一组名称/值对; 名称是string
类型,值是Java原语。 -
TextMessage
:包含一个String
。 -
ObjectMessage
:包含一个可Serializable
Java对象; 可以使用JDK 1.2集合类。 -
BytesMessage
:包含未解释的字节流; 允许对正文进行编码以匹配现有的邮件格式。
每个提供程序都提供特定于其产品的实现这些接口的类。 重要的是要注意,JMS规范要求提供者必须准备好接受和处理不是其自身Message
类之一实例的Message
对象。
尽管提供者可能无法像提供者自己的实现之一那样有效地处理这些“异类”对象,但必须对它们进行处理以确保所有JMS提供者的互操作性。
交易次数
JMS事务将一组产生的消息和一组消耗的消息分组为一个原子工作单元。 如果在事务期间发生错误,则可以“撤消”在错误之前发生的消息的产生和使用。
Session
对象控制事务,并且在创建Session
可以将其表示为事务 。 事务处理Session
总是有一个当前事务,那就是,有没有begin()
; commit()
和rollback()
结束一个事务并自动开始另一个事务。
Java事务API(JTA) XAResource
API可以支持分布式事务,尽管这对于提供程序是可选的。
致谢
确认是一种机制,通过该机制可以通知提供者已成功接收到消息。
如果接收消息的Session
已处理,则将自动处理确认。 如果Session
,则在创建Session
时确定确认的类型。
确认分为三种:
-
Session.DUPS_OK_ACKNOWLEDGE
:消息传递的延迟确认; 通过最小化防止重复的工作来减少开销; 仅在预期有重复消息且可以处理时才应使用。 -
Session.AUTO_ACKNOWLEDGE
:完成接收消息的方法后,将自动确认消息传递。 -
Session.CLIENT_ACKNOWLEDGE
:通过在Message
上调用acknowledge()
方法来显式确认消息传递。
讯息选择
JMS为JMS程序提供了一种称为消息选择器的机制,以对其接收到的消息进行过滤和分类。
消息选择器是一个String
,其中包含一个表达式,其语法基于SQL92的子集。 尝试接收消息时将评估消息选择器,并且只有符合选择器选择标准的消息才可供程序使用。
选择基于与标题字段和属性的匹配; 正文值不能用于选择。 JMS规范中详细提供了消息选择器的语法。
JMS和XML
JMS的作者在假定String
消息将被广泛使用的情况下包括TextMessage
消息类型。
他们的理由是,XML将成为一种表示消息内容的流行(如果不是最流行的)方式。 事实证明,便携式传输机制(JMS)与便携式数据表示(XML)结合在一起,将成为企业应用程序集成(EAI)和其他数据交换领域中的强大工具。
JMS和J2EE
J2EE 1.2版要求兼容的应用程序服务器具有JMS API,但没有强制要求存在JMS提供程序。
J2EE 1.3版要求应用程序服务器提供JMS提供程序。 J2EE版本1.3还引入了消息驱动bean ,作为EJB 2.0规范的一部分,向Enterprise JavaBeans容器添加了异步通知功能。 消息驱动bean实现了MessageListener
接口(见MessageListener
)本教程后面),并通过在消息中的在部署时所指定的目的地的到达EJB容器调用。 消息驱动的bean包含用于处理消息的业务逻辑,包括在需要时调用其他企业bean。
J2EE 1.4版要求J2EE产品包括一个JMS 1.1版提供程序,该提供程序同时支持点对点和发布/订阅消息传递。 它指定J2EE应用程序将不使用JMS客户端API进行事务处理。 事务将由J2EE容器处理。 J2EE 1.4版还要求Web和EJB容器中的组件在每个连接中不能创建一个以上活动的Session
。
JMS 1.1的新增功能:通用接口
JMS 1.1简介
在本节中,我们将研究用于JMS客户端编程的每个重要的JMS通用接口及其一些方法。 重要的是要记住,尽管公共接口是独立于域的,但是客户端代码的行为与运行时运行域的域特定行为相匹配。
在下一节中,我们将看一些执行JMS消息处理的示例代码。
ConnectionFactory
ConnectionFactory
是一个受管理对象,可以从JNDI中检索该对象以创建与提供程序的连接。 它包含一个createConnection()
方法,该方法返回一个Connection
对象。
Connection
Connection
封装了到提供程序的活动连接。 它的一些方法是:
-
createSession(boolean, int)
:返回一个Session
对象。boolean
参数指示Session
是否被处理;int
表示确认模式(请参阅确认 )。 -
start()
:激活从提供程序传递消息。 -
stop()
:暂时停止传递消息; 可以使用start()
重新start()
传递。 -
close()
:关闭与提供程序的连接,并释放代表它的所有资源。
Session
Session
是用于发送和接收消息的单线程上下文。 它的一些方法是:
-
createProducer(Destination)
:返回一个MessageProducer
对象,以将消息发送到指定的Destination
。 -
createConsumer(Destination)
:返回一个MessageConsumer
对象,以从指定的Destination
接收消息。 -
commit()
:提交当前事务的所有消耗或产生的消息。 -
rollback()
:rollback()
当前事务的所有消耗或产生的消息。 -
create<MessageType>Message(...)
:返回<MessageType>Message
多种方法,例如MapMessage
,TextMessage
等。
Destination
Destination
封装了消息的目标。 它是从JNDI检索的管理对象。
MessageProducer
MessageProducer
用于发送消息。 它的一些方法是:
-
send(Message)
:发送指示的Message
。 -
setDeliveryMode(int)
:设置后续发送消息的传递模式; 有效值为DeliveryMode.PERSISTENT
和DeliveryMode.NON_PERSISTENT
。 -
setPriority(int)
:设置后续发送消息的优先级; 有效值为0到9。 -
setTimeToLive(long)
:设置过期时间(以毫秒为单位),以秒为单位发送后续消息。
MessageConsumer
MessageConsumer
用于接收消息。 它的一些方法是:
-
receive()
:返回下一条到达的消息; 此方法将阻塞,直到有消息可用为止。 -
receive(long)
:接收long
毫秒内到达的下一条消息; 如果在时间限制内没有消息到达,则此方法返回null
。 -
receiveNoWait
:如果有立即可用的消息,则接收下一条消息; 如果没有可用消息,则此方法返回null
。 -
setMessageListener(MessageListener)
:设置MessageListener
;MessageListener
对象在到达消息时即异步接收消息(请参阅MessageListener
)。
MessageListener
MessageListener
是具有单个方法onMessage(Message)
的接口,该方法提供onMessage(Message)
异步接收和处理。
此接口应由客户端类实现,并使用setMessageListener(MessageListener)
方法将该类的实例传递给MessageConsumer
对象。 当消息到达目的地时,它使用onMessage(Message)
方法传递给对象。
具有通用接口的客户端编程
具有通用接口的客户端编程介绍
在本节中,我们将遍历两个执行JMS客户端消息传递的程序-Sender.java和Receiver.java。
我们将在小节中查看代码,并描述每个节的功能。 您可以在附录: Sender.java的 代码清单和Receiver.java的 代码清单中看到完整的清单。
Sender
:提示输入JNDI名称
所有示例程序都是使用System.in
作为输入,而使用System.out
作为输出的命令行程序。
Sender
类有两个方法: main(String[])
和send()
。 main(String[])
方法仅实例化一个Sender
并调用其send()
方法。
send()
方法的第一部分提示将用于发送消息的受管理对象的JNDI名称。
import java.io.*;
import javax.jms.*;
import javax.naming.*;
public class Sender {
public static void main(String[] args) {
new Sender().send();
}
public void send() {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
try {
//Prompt for JNDI names
System.out.println("Enter ConnectionFactory name:");
String factoryName = reader.readLine();
System.out.println("Enter Destination name:");
String destinationName = reader.readLine();
. . .
Sender
:查找受管理的对象
send()
方法的下一部分使用先前输入的名称在JNDI中查找受管理对象。
通过实例化InitialContext
对象来访问JNDI。 通过调用lookup(String)
方法来检索受管理的对象,并传入要检索的对象的名称。 请注意, lookup(String)
方法返回Object
,因此必须对返回的对象执行类型转换。
. . .
//Look up administered objects
InitialContext initContext = new InitialContext();
ConnectionFactory factory =
(ConnectionFactory) initContext.lookup(factoryName);
Destination destination = (Destination) initContext.lookup(destinationName);
initContext.close();
. . .
Sender
:创建JMS对象
现在,我们创建了发送消息所需的JMS对象。 请注意,我们不会使用new
直接实例化这些对象。 通过在另一个对象上调用方法来创建所有对象。
首先,我们使用ConnectionFactory
创建一个Connection
。 然后,我们使用该Connection
创建一个Session
。
Session
未处理( false
),将使用自动确认( Session.AUTO_ACKNOWLEDGE
)。
最后,我们创建Sender
以将消息发送到我们从JNDI检索到的Destination
。
. . .
//Create JMS objects
Connection connection = factory.createConnection();
Session session =
connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer sender = session.createProducer(destination);
. . .
Sender
:发送消息
现在我们可以发送消息了。 在本节中,我们进入一个循环,在该循环中,提示您输入要发送的消息文本。 如果用户键入quit ,则循环退出。
否则,我们将根据输入的文本构建一个TextMessage
并使用MessageProducer
发送消息,然后返回循环的顶部。
. . .
//Send messages
String messageText = null;
while (true) {
System.out.println("Enter message to send or 'quit':");
messageText = reader.readLine();
if ("quit".equals(messageText))
break;
TextMessage message = session.createTextMessage(messageText);
sender.send(message);
}
. . .
Sender
:退出
循环退出后,我们关闭Connection
。 关闭Connection
自动关闭Session
和MessageProducer
。
. . .
//Exit
System.out.println("Exiting...");
reader.close();
connection.close();
System.out.println("Goodbye!");
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
}
Receiver
:提示输入JNDI名称并查找受管理的对象
与Sender
类类似, Receiver
类具有main(String[])
方法,该方法简单地实例化Receiver
并调用其主要方法receive()
。
提示输入JNDI名称并查找受管理对象的代码与Sender
的代码相同。
但是,此类中有两个区别:
-
boolean stop
实例变量用于指示程序应退出。 -
Receiver
实现MessageListener
接口,以便异步接收消息。
import java.io.*;
import javax.jms.*;
import javax.naming.*;
public class Receiver implements MessageListener {
private boolean stop = false;
public static void main(String[] args) {
new Receiver().receive();
}
public void receive() {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
try {
//Prompt for JNDI names
System.out.println("Enter ConnectionFactory name:");
String factoryName = reader.readLine();
System.out.println("Enter Destination name:");
String destinationName = reader.readLine();
reader.close();
//Look up administered objects
InitialContext initContext = new InitialContext();
ConnectionFactory factory =
(ConnectionFactory) initContext.lookup(factoryName);
Destination destination = (Destination) initContext.lookup(destinationName);
initContext.close();
. . .
Receiver
:创建JMS对象
将按照在Sender
中的方式创建Connection
和Session
,然后创建MessageConsumer
。
接下来,将调用setMessageListener()
,并传入this
— Receiver
的本地实例,您将回想起该实例,该实例实现了MessageListener
接口。
最后,开始Connection
以允许接收消息。
. . .
//Create JMS objects
Connection connection = factory.createConnection();
Session session =
connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageConsumer receiver = session.createConsumer(queue);
receiver.setMessageListener(this);
connection.start();
. . .
Receiver
:等待stop
并退出
接下来,程序进入循环,当stop
变量变为true时将退出。 在循环中,线程Hibernate一秒钟。 退出循环后,将关闭Connection
并终止程序。
. . .
//Wait for stop
while (!stop) {
Thread.sleep(1000);
}
//Exit
System.out.println("Exiting...");
connection.close();
System.out.println("Goodbye!");
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
. . .
Receiver
: onMessage(Message)
方法
因为Receiver
实现了MessageListener
接口,所以必须存在Receiver
类的onMessage(Message)
方法。
收到消息后,将以传递的Message
作为参数来调用此方法。
在我们的实现中,我们获取消息的文本内容并将其打印到System.out
。 然后,我们检查消息是否等于stop ,如果是,则将stop
变量设置为true
。 这样可以终止receive()
方法中的循环。
. . .
public void onMessage(Message message) {
try {
String msgText = ((TextMessage) message).getText();
System.out.println(msgText);
if ("stop".equals(msgText))
stop = true;
} catch (JMSException e) {
e.printStackTrace();
stop = true;
}
}
}
运行程序
如《 入门指南》中所述,您需要javax.naming
和javax.jms
包来编译Sender
和Receiver
程序。
Before you run the programs, you need to use the administration tool supplied by your JMS provider to create the ConnectionFactory
and Destination
administered objects and place them in the JNDI namespace.
You also need to make sure that the provider's JMS implementation classes are in your classpath.
You can then run both of these programs at the same time, supplying the same JNDI names for the ConnectionFactory
and Destination
, and send messages from the Sender
to the Receiver
.
Point-to-point interfaces
Point-to-point interfaces introduction
In this section, we'll look at each of the important JMS interfaces for point-to-point programming and some of their methods.
In the next section (Point-to-point programming ), we'll look at some sample code that performs point-to-point message processing.
Remember: The point-to-point and pub/sub interfaces are included in JMS version 1.1 only for backward compatibility. If you are doing new development, use the common interfaces covered in the previous two sections (New in JMS 1.1: Common interfaces and Client programming with common interfaces ).
QueueConnectionFactory
QueueConnectionFactory
is an administered object that is retrieved from JNDI to create a connection to a provider. It contains a createQueueConnection()
method, which returns a QueueConnection
object.
QueueConnection
QueueConnection
encapsulates an active connection to a provider. Some of its methods are:
-
createQueueSession(boolean, int)
: Returns aQueueSession
object. Theboolean
parameter indicates whether theQueueSession
is transacted or not; theint
indicates the acknowledgment mode (see Acknowledgment ). -
start()
(inherited fromConnection
): Activates the delivery of messages from the provider. -
stop()
(inherited fromConnection
): Temporarily stops delivery of messages; delivery can be restarted withstart()
. -
close()
(inherited fromConnection
): Closes the connection to the provider and releases all resources held in its behalf.
QueueSession
QueueSession
is the single-threaded context for sending and receiving PTP messages. Some of its methods are:
-
createSender(Queue)
: Returns aQueueSender
object to send messages to the specifiedQueue
. -
createReceiver(Queue)
: Returns aQueueReceiver
object to receive messages from the specifiedQueue
. -
createBrowser(Queue)
(inherited fromSession
): Returns aQueueBrowser
object to browse messages on the specifiedQueue
. -
commit()
(inherited fromSession
): Commits all consumed or produced messages for the current transaction. -
rollback()
(inherited fromSession
): Rolls back all consumed or produced messages for the current transaction. -
create<MessageType>Message(...)
(inherited fromSession
): A variety of methods that return a<MessageType>Message
-- for example,MapMessage
,TextMessage
, and so on.
Queue
Queue
encapsulates a point-to-point destination. It is an administered object that is retrieved from JNDI.
QueueSender
QueueSender
is used to send point-to-point messages. Some of its methods are:
-
send(Message)
: Sends the indicatedMessage
. -
setDeliveryMode(int)
(inherited fromMessageProducer
): Sets the delivery mode for subsequent messages sent; valid values areDeliveryMode.PERSISTENT
andDeliveryMode.NON_PERSISTENT
. -
setPriority(int)
(inherited fromMessageProducer
): Sets the priority for subsequent messages sent; valid values are 0 through 9. -
setTimeToLive(long)
(inherited fromMessageProducer
): Sets the duration before expiration, in milliseconds, of subsequent messages sent.
QueueReceiver
QueueReceiver
is used to receive point-to-point messages. Some of its methods are:
-
receive()
(inherited fromMessageConsumer
): Returns the next message that arrives; this method blocks until a message is available. -
receive(long)
(inherited fromMessageConsumer
): Receives the next message that arrives withinlong
milliseconds; this method returnsnull
if no message arrives within the time limit. -
receiveNoWait
(inherited fromMessageConsumer
): Receives the next message if one is immediately available; this method returnsnull
if no message is available. -
setMessageListener(MessageListener)
(inherited fromMessageConsumer
): Sets theMessageListener
; theMessageListener
object receives messages as they arrive, that is, asynchronously (seeMessageListener
).
QueueBrowser
When QueueReceiver
is used to receive messages, the messages are removed from the queue when they are received. QueueBrowser
is used to look at messages on a queue without removing them. The method for doing that is getEnumeration()
, which returns a java.util.Enumeration
that can be used to scan the messages in the queue; changes to the queue (arriving and expiring of messages) may or may not be visible.
Point-to-point programming
Point-to-point programming introduction
In this section, we'll walk through two programs that do point-to-point messaging -- QSender.java and QReceiver.java.
We'll look at the code in small sections and describe what each section does. You can see the complete listings in the Appendix: Code listing for QSender.java and Code listing for QReceiver.java .
QSender
: Prompt for JNDI names
All of the sample programs are command-line programs that use System.in
for input and System.out
for output.
The QSender
class has two methods: main(String[])
and send()
. The main(String[])
method merely instantiates a QSender
and calls its send()
method.
The first section of the send()
method prompts for the JNDI names of the administered objects that will be used to send messages.
import java.io.*;
import javax.jms.*;
import javax.naming.*;
public class QSender {
public static void main(String[] args) {
new QSender().send();
}
public void send() {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
try {
//Prompt for JNDI names
System.out.println("Enter QueueConnectionFactory name:");
String factoryName = reader.readLine();
System.out.println("Enter Queue name:");
String queueName = reader.readLine();
. . .
QSender
: Look up administered objects
The next section of the send()
method looks up the administered objects in JNDI, using the names input earlier.
JNDI is accessed by instantiating an InitialContext
object; the administered objects are retrieved by calling the lookup(String)
method, passing in the name of the object to be retrieved. Note that the lookup(String)
method returns Object
, so a typecast must be performed on the returned object.
. . .
//Look up administered objects
InitialContext initContext = new InitialContext();
QueueConnectionFactory factory =
(QueueConnectionFactory) initContext.lookup(factoryName);
Queue queue = (Queue) initContext.lookup(queueName);
initContext.close();
. . .
QSender
: Create JMS objects
Now, we create the JMS objects we need to send messages. Note that we don't directly instantiate these objects using new
. All of the objects are created by calling a method on another object.
First, we use the QueueConnectionFactory
to create a QueueConnection
. We then use that QueueConnection
to create a QueueSession
.
The QueueSession
is not transacted ( false
) and will use automatic acknowledgment ( Session.AUTO_ACKNOWLEDGE
).
Finally, we create the QueueSender
to send messages to the Queue
we retrieved from JNDI.
. . .
//Create JMS objects
QueueConnection connection = factory.createQueueConnection();
QueueSession session =
connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
QueueSender sender = session.createSender(queue);
. . .
QSender
: Send messages
Now we're ready to send messages. In this section, we enter a loop where we prompt for the text of a message to send. If the user types quit , the loop exits.
Otherwise, we build a TextMessage
from the entered text and use the QueueSender
to send the message, then return to the top of the loop.
. . .
//Send messages
String messageText = null;
while (true) {
System.out.println("Enter message to send or 'quit':");
messageText = reader.readLine();
if ("quit".equals(messageText))
break;
TextMessage message = session.createTextMessage(messageText);
sender.send(message);
}
. . .
QSender
: Exit
Once the loop exits, we close the QueueConnection
. Closing the QueueConnection
automatically closes the QueueSession
and QueueSender
.
. . .
//Exit
System.out.println("Exiting...");
reader.close();
connection.close();
System.out.println("Goodbye!");
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
}
QReceiver
: Prompt for JNDI names and look up administered objects
The QReceiver
class, like the QSender
class, has a main(String[])
method that simply instantiates a QReceiver
and calls its primary method, receive()
.
The code for prompting for JNDI names and doing the lookup of administered objects is identical to that in QSender
.
There are two differences in this class, however:
- The
boolean stop
instance variable is used to indicate that the program should exit. -
QReceiver
implements theMessageListener
interface in order to receive messages asynchronously.
import java.io.*;
import javax.jms.*;
import javax.naming.*;
public class QReceiver implements MessageListener {
private boolean stop = false;
public static void main(String[] args) {
new QReceiver().receive();
}
public void receive() {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
try {
//Prompt for JNDI names
System.out.println("Enter QueueConnectionFactory name:");
String factoryName = reader.readLine();
System.out.println("Enter Queue name:");
String queueName = reader.readLine();
reader.close();
//Look up administered objects
InitialContext initContext = new InitialContext();
QueueConnectionFactory factory =
(QueueConnectionFactory) initContext.lookup(factoryName);
Queue queue = (Queue) initContext.lookup(queueName);
initContext.close();
. . .
QReceiver
: Create JMS objects
The QueueConnection
and QueueSession
are created as they are in QSender
, and then a QueueReceiver
is created.
Next, setMessageListener()
is called, passing in this
-- the local instance of QReceiver
, which you will recall implements the MessageListener
interface.
Finally, the QueueConnection
is started to allow messages to be received.
. . .
//Create JMS objects
QueueConnection connection = factory.createQueueConnection();
QueueSession session =
connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
QueueReceiver receiver = session.createReceiver(queue);
receiver.setMessageListener(this);
connection.start();
. . .
QReceiver
: Wait for stop
and exit
Next, the program goes into a loop that will exit when the stop
variable becomes true. In the loop, the thread sleeps for one second. Once the loop has exited, the QueueConnection
is closed and the program terminates.
. . .
//Wait for stop
while (!stop) {
Thread.sleep(1000);
}
//Exit
System.out.println("Exiting...");
connection.close();
System.out.println("Goodbye!");
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
. . .
QReceiver
: onMessage(Message)
method
The presence of the QReceiver
class's onMessage(Message)
method is required because QReceiver
implements the MessageListener
interface.
When a message is received, this method is called with the Message
passed as the parameter.
In our implementation, we get the text content of the message and print it to System.out
. We then check to see if the message equals stop , and if it does, the stop
variable is set to true
; this allows the loop in the receive()
method to terminate.
. . .
public void onMessage(Message message) {
try {
String msgText = ((TextMessage) message).getText();
System.out.println(msgText);
if ("stop".equals(msgText))
stop = true;
} catch (JMSException e) {
e.printStackTrace();
stop = true;
}
}
}
Pub/sub interfaces
Pub/sub interfaces introduction
Now let's look at the pub/sub interfaces. As we go through them, notice how they are very much like the PTP interfaces, except for the names and a few other differences.
Remember: The point-to-point and pub/sub interfaces are included in JMS version 1.1 only for backward compatibility. If you are doing new development, use the common interfaces covered in the New in JMS 1.1: Common interfaces and Client programming with common interfaces sections.
TopicConnectionFactory
TopicConnectionFactory
is an administered object that is retrieved from JNDI in order to create a connection to a provider. It contains a createTopicConnection()
method, which returns a TopicConnection
object.
TopicConnection
TopicConnection
encapsulates an active connection to a provider. Some of its methods are:
-
createTopicSession(boolean, int)
: Returns aTopicSession
object. Theboolean
parameter indicates whether theTopicSession
is transacted; theint
indicates the acknowledgment mode (see Acknowledgment ). -
start()
(inherited fromConnection
): Activates the delivery of messages from the provider. -
stop()
(inherited fromConnection
): Temporarily stops delivery of messages; delivery can be restarted withstart()
. -
close()
(inherited fromConnection
): Closes the connection to the provider and releases all resources held in its behalf.
TopicSession
TopicSession
is the single-threaded context for sending and receiving pub/sub messages. Some of its methods are:
-
createPublisher(Topic)
: Returns aTopicPublisher
object to send messages to the specifiedTopic
. -
createSubscriber(Topic)
: Returns aTopicSubscriber
object to receive messages from the specifiedTopic
. This subscriber is non-durable ; that is, the subscription will last only for the lifetime of the object and will receive messages only when it is active. -
createDurableSubscriber(Topic, String)
: Returns aTopicSubscriber
object to receive messages from the specifiedTopic
, giving theString
name to the subscriber. Messages for a durable subscriber will be retained by JMS if the object is not active and will be delivered to subsequent subscriber objects that are created with the same name. -
unsubscribe(String)
: Ends the subscription with theString
name. -
commit()
(inherited fromSession
): Commits all consumed or produced messages for the current transaction. -
rollback()
(inherited fromSession
): Rolls back all consumed or produced messages for the current transaction. -
create<MessageType>Message(...)
(inherited fromSession
): A variety of methods that return a<MessageType>Message
, such asMapMessage
,TextMessage
, and so on.
Topic
Topic
encapsulates a pub/sub destination. It is an administered object that is retrieved from JNDI.
TopicPublisher
TopicPublisher
is used to send pub/sub messages. Some of its methods are:
-
publish(Message)
: Publishes the indicatedMessage
. -
setDeliveryMode(int)
(inherited fromMessageProducer
): Sets the delivery mode for subsequent messages sent; valid values areDeliveryMode.PERSISTENT
andDeliveryMode.NON_PERSISTENT
. -
setPriority(int)
(inherited fromMessageProducer
): Sets the priority for subsequent messages sent; valid values are 0 through 9. -
setTimeToLive(long)
(inherited fromMessageProducer
): Sets the duration before expiration, in milliseconds, of subsequent messages sent.
TopicSubscriber
TopicSubscriber
is used to receive point-to-point messages. Some of its methods are:
-
receive()
(inherited fromMessageConsumer
): Returns the next message that arrives; this method blocks until a message is available. -
receive(long)
(inherited fromMessageConsumer
): Receives the next message that arrives withinlong
milliseconds; this method returnsnull
if no message arrives within the time limit. -
receiveNoWait
(inherited fromMessageConsumer
): Receives the next message if one is immediately available; this method returnsnull
if no message is available. -
setMessageListener(MessageListener)
(inherited fromMessageConsumer
): Sets theMessageListener
; theMessageListener
object receives messages as they arrive, that is, asynchronously (seeMessageListener
).
Pub/sub programming
The same, but different
Two pub/sub programs are available in the Appendix -- Code listing for TPublisher.java and Code listing for TSubscriber.java . We won't go through them step-by-step as we did the PTP programs because, other than the types of JMS interfaces used, they are identical to QSender.java and QReceiver.java.
You need to set up TopicConnectionFactory
and Topic
administered objects before you run these programs.
You'll see the difference between these and the PTP programs once you run them. If you run multiple instances of QReceiver
using the same QueueConnectionFactory
and Queue
, you'll see that as you send messages from QSender
, only one of the QReceiver
instances receives each message sent.
If you run multiple instances of TSubscriber
, you'll see that all messages sent from TPublisher
are received by all instances of TSubscriber
.
Wrapping up
摘要
This tutorial has provided an introduction and overview of the Java Message Service and its functionality and capabilities. It has also demonstrated basic programming techniques for creating JMS programs and provided sample code to illustrate those programs.
We did not look at every interface and class in the JMS API, nor did we look at every method on those interfaces we did examine. The Related topics provide some pointers to materials to help you do that.
The goal here is to get you started with JMS and give you some basic working programs to learn from. Once you have the sample programs up and running, experiment by modifying them to use message selection, durable subscriptions, and some of the other capabilities of JMS that we touched on here but did not demonstrate in the sample programs.
附录
Code listing for Sender.java
import java.io.*;
import javax.jms.*;
import javax.naming.*;
public class Sender {
public static void main(String[] args) {
new Sender().send();
}
public void send() {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
try {
//Prompt for JNDI names
System.out.println("Enter ConnectionFactory name:");
String factoryName = reader.readLine();
System.out.println("Enter Destination name:");
String destinationName = reader.readLine();
//Look up administered objects
InitialContext initContext = new InitialContext();
ConnectionFactory factory =
(ConnectionFactory) initContext.lookup(factoryName);
Destination destination = (Destination) initContext.lookup(destinationName);
initContext.close();
//Create JMS objects
Connection connection = factory.createConnection();
Session session =
connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer sender = session.createProducer(queue);
//Send messages
String messageText = null;
while (true) {
System.out.println("Enter message to send or 'quit':");
messageText = reader.readLine();
if ("quit".equals(messageText))
break;
TextMessage message = session.createTextMessage(messageText);
sender.send(message);
}
//Exit
System.out.println("Exiting...");
reader.close();
connection.close();
System.out.println("Goodbye!");
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
}
Code listing for Receiver.java
import java.io.*;
import javax.jms.*;
import javax.naming.*;
public class Receiver implements MessageListener {
private boolean stop = false;
public static void main(String[] args) {
new Receiver().receive();
}
public void receive() {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
try {
//Prompt for JNDI names
System.out.println("Enter ConnectionFactory name:");
String factoryName = reader.readLine();
System.out.println("Enter Destination name:");
String destinationName = reader.readLine();
reader.close();
//Look up administered objects
InitialContext initContext = new InitialContext();
ConnectionFactory factory =
(ConnectionFactory) initContext.lookup(factoryName);
Destination destination = (Destination) initContext.lookup(destinationName);
initContext.close();
//Create JMS objects
Connection connection = factory.createConnection();
Session session =
connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageConsumer receiver = session.createConsumer(queue);
receiver.setMessageListener(this);
connection.start();
//Wait for stop
while (!stop) {
Thread.sleep(1000);
}
//Exit
System.out.println("Exiting...");
connection.close();
System.out.println("Goodbye!");
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
public void onMessage(Message message) {
try {
String msgText = ((TextMessage) message).getText();
System.out.println(msgText);
if ("stop".equals(msgText))
stop = true;
} catch (JMSException e) {
e.printStackTrace();
stop = true;
}
}
}
Code listing for QSender.java
import java.io.*;
import javax.jms.*;
import javax.naming.*;
public class QSender {
public static void main(String[] args) {
new QSender().send();
}
public void send() {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
try {
//Prompt for JNDI names
System.out.println("Enter QueueConnectionFactory name:");
String factoryName = reader.readLine();
System.out.println("Enter Queue name:");
String queueName = reader.readLine();
//Look up administered objects
InitialContext initContext = new InitialContext();
QueueConnectionFactory factory =
(QueueConnectionFactory) initContext.lookup(factoryName);
Queue queue = (Queue) initContext.lookup(queueName);
initContext.close();
//Create JMS objects
QueueConnection connection = factory.createQueueConnection();
QueueSession session =
connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
QueueSender sender = session.createSender(queue);
//Send messages
String messageText = null;
while (true) {
System.out.println("Enter message to send or 'quit':");
messageText = reader.readLine();
if ("quit".equals(messageText))
break;
TextMessage message = session.createTextMessage(messageText);
sender.send(message);
}
//Exit
System.out.println("Exiting...");
reader.close();
connection.close();
System.out.println("Goodbye!");
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
}
Code listing for QReceiver.java
import java.io.*;
import javax.jms.*;
import javax.naming.*;
public class QReceiver implements MessageListener {
private boolean stop = false;
public static void main(String[] args) {
new QReceiver().receive();
}
public void receive() {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
try {
//Prompt for JNDI names
System.out.println("Enter QueueConnectionFactory name:");
String factoryName = reader.readLine();
System.out.println("Enter Queue name:");
String queueName = reader.readLine();
reader.close();
//Look up administered objects
InitialContext initContext = new InitialContext();
QueueConnectionFactory factory =
(QueueConnectionFactory) initContext.lookup(factoryName);
Queue queue = (Queue) initContext.lookup(queueName);
initContext.close();
//Create JMS objects
QueueConnection connection = factory.createQueueConnection();
QueueSession session =
connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
QueueReceiver receiver = session.createReceiver(queue);
receiver.setMessageListener(this);
connection.start();
//Wait for stop
while (!stop) {
Thread.sleep(1000);
}
//Exit
System.out.println("Exiting...");
connection.close();
System.out.println("Goodbye!");
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
public void onMessage(Message message) {
try {
String msgText = ((TextMessage) message).getText();
System.out.println(msgText);
if ("stop".equals(msgText))
stop = true;
} catch (JMSException e) {
e.printStackTrace();
stop = true;
}
}
}
Code listing for TPublisher.java
import java.io.*;
import javax.jms.*;
import javax.naming.*;
public class TPublisher {
public static void main(String[] args) {
new TPublisher().publish();
}
public void publish() {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
try {
//Prompt for JNDI names
System.out.println("Enter TopicConnectionFactory name:");
String factoryName = reader.readLine();
System.out.println("Enter Topic name:");
String topicName = reader.readLine();
//Look up administered objects
InitialContext initContext = new InitialContext();
TopicConnectionFactory factory =
(TopicConnectionFactory) initContext.lookup(factoryName);
Topic topic = (Topic) initContext.lookup(topicName);
initContext.close();
//Create JMS objects
TopicConnection connection = factory.createTopicConnection();
TopicSession session =
connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
TopicPublisher publisher = session.createPublisher(topic);
//Send messages
String messageText = null;
while (true) {
System.out.println("Enter message to send or 'quit':");
messageText = reader.readLine();
if ("quit".equals(messageText))
break;
TextMessage message = session.createTextMessage(messageText);
publisher.publish(message);
}
//Exit
System.out.println("Exiting...");
reader.close();
connection.close();
System.out.println("Goodbye!");
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
}
Code listing for TSubscriber.java
import java.io.*;
import javax.jms.*;
import javax.naming.*;
public class TSubscriber implements MessageListener {
private boolean stop = false;
public static void main(String[] args) {
new TSubscriber().subscribe();
}
public void subscribe() {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
try {
//Prompt for JNDI names
System.out.println("Enter TopicConnectionFactory name:");
String factoryName = reader.readLine();
System.out.println("Enter Topic name:");
String topicName = reader.readLine();
reader.close();
//Look up administered objects
InitialContext initContext = new InitialContext();
TopicConnectionFactory factory =
(TopicConnectionFactory) initContext.lookup(factoryName);
Topic topic = (Topic) initContext.lookup(topicName);
initContext.close();
//Create JMS objects
TopicConnection connection = factory.createTopicConnection();
TopicSession session =
connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
TopicSubscriber subscriber = session.createSubscriber(topic);
subscriber.setMessageListener(this);
connection.start();
//Wait for stop
while (!stop) {
Thread.sleep(1000);
}
//Exit
System.out.println("Exiting...");
connection.close();
System.out.println("Goodbye!");
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
public void onMessage(Message message) {
try {
String msgText = ((TextMessage) message).getText();
System.out.println(msgText);
if ("stop".equals(msgText))
stop = true;
} catch (JMSException e) {
e.printStackTrace();
stop = true;
}
}
}
翻译自: https://www.ibm.com/developerworks/java/tutorials/j-jms/j-jms-updated.html