java 消息服务_Java消息服务简介

入门

我应该学习本教程吗?

本教程概述了Java消息服务(JMS),并提供了开发使用它的程序的基础。 JMS由Sun Microsystems开发,旨在为Java程序提供一种访问企业消息传递系统(也称为面向消息的中间件 (MOM))的方式。 MOM通过以间接方式通过中介在应用程序之间提供异步数据传递,从而提供了一种以松散耦合,灵活的方式集成应用程序的机制。

在学习本教程之前,您应该熟悉Java编程和面向对象的编程概念。

要编写本教程中描述的程序,您需要一个编辑环境。 它可以像操作系统编辑器一样基本。 在开发环境中,许多人使用集成开发环境(IDE),因为它具有专门为编写和测试代码而设计的调试器和其他功能。

要编译程序,您需要Java编译器(javac.exe)。 您还将需要javax.jms包中的JMS类和javax.naming包中的Java命名和目录接口(JNDI)类。 您可以从Sun: JMSJNDI下载这些文件。

要执行和测试程序,您需要访问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通信。

MOM将消息路由到应用程序B,该应用程序B可以存在于完全不同的计算机上。 MOM处理网络通信。 如果网络连接不可用,MOM将存储该消息,直到连接可用为止,然后将其转发给应用程序B。

灵活性的另一方面是,当应用程序A发送其消息时,应用程序B甚至可能没有执行。 MOM将保留该消息,直到应用程序B开始执行并尝试检索其消息为止。 这也可以防止应用程序A在等待应用程序B接收消息时阻塞。

这种异步通信要求应用程序的设计与当今大多数应用程序的设计有所不同,但是对于与时间无关或并行处理,这可能是非常有用的方法。

松耦合

企业消息传递系统的真正力量在于应用程序的松耦合 。 在上一节的图中,应用程序A发送其指示特定目的地的消息,例如“订单处理”。 今天,应用程序B提供了订单处理功能。

但是,将来,我们可以用不同的订单处理程序替换应用程序B,而应用程序A绝不明智。 它将继续将其消息发送到“订单处理”,并且消息将继续被处理。

同样,我们可以替换应用程序A,只要替换继续发送消息以进行“订单处理”,订单处理程序就不需要知道有新的应用程序发送订单。

发布和订阅

最初,企业消息传递系统是为了实现点对点模型 (PTP)而开发的,在该模型中,由一个应用程序生成的每个消息都被另一个应用程序接收。 近年来,出现了一种新模型,称为发布和订阅 (或pub / sub)。

发布/订阅将PTP模型中的单个目标替换为内容层次结构,即主题 。 发送应用程序会发布其消息,表明该消息表示有关层次结构中某个主题的信息。

希望接收这些消息的应用程序订阅该主题。 订阅包含子主题的层次结构中的主题,使订户可以接收发布到该主题及其子主题的所有消息。

该图说明了发布和订阅模型。

发布和订阅模型

多个应用程序可以同时订阅和发布主题的消息,并且这些应用程序彼此之间保持匿名。 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 QueueReceiverQueueBrowser 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 QueueReceiverQueueBrowser TopicSubscriber

使用通用接口统一域会导致某些特定于域的类继承不适合该域的方法。 如果这在客户端代码中发生,则要求JMS提供者抛出IllegalStateException

开发JMS程序

一个典型的JMS程序通过以下步骤开始生成和使用消息:

  1. 通过JNDI查找ConnectionFactory
  2. 通过JNDI查找一个或多个Destination
  3. 使用ConnectionFactory创建一个Connection
  4. 使用Connection创建一个或多个Session
  5. 使用SessionDestination来创建所需的MessageProducerMessageConsumer
  6. 启动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.PERSISTENTDeliveryMode.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多种方法,例如MapMessageTextMessage等。

Destination

Destination封装了消息的目标。 它是从JNDI检索的管理对象。

MessageProducer

MessageProducer用于发送消息。 它的一些方法是:

  • send(Message) :发送指示的Message
  • setDeliveryMode(int) :设置后续发送消息的传递模式; 有效值为DeliveryMode.PERSISTENTDeliveryMode.NON_PERSISTENT
  • setPriority(int) :设置后续发送消息的优先级; 有效值为0到9。
  • setTimeToLive(long) :设置过期时间(以毫秒为单位),以秒为单位发送后续消息。

MessageConsumer

MessageConsumer用于接收消息。 它的一些方法是:

  • receive() :返回下一条到达的消息; 此方法将阻塞,直到有消息可用为止。
  • receive(long) :接收long毫秒内到达的下一条消息; 如果在时间限制内没有消息到达,则此方法返回null
  • receiveNoWait :如果有立即可用的消息,则接收下一条消息; 如果没有可用消息,则此方法返回null
  • setMessageListener(MessageListener) :设置MessageListenerMessageListener对象在到达消息时即异步接收消息(请参阅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自动关闭SessionMessageProducer

. . .
            //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中的方式创建ConnectionSession ,然后创建MessageConsumer

接下来,将调用setMessageListener() ,并传入thisReceiver的本地实例,您将回想起该实例,该实例实现了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);
        }
    }
    . . .

ReceiveronMessage(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.namingjavax.jms包来编译SenderReceiver程序。

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 a QueueSession object. The boolean parameter indicates whether the QueueSession is transacted or not; the int indicates the acknowledgment mode (see Acknowledgment ).
  • start() (inherited from Connection ): Activates the delivery of messages from the provider.
  • stop() (inherited from Connection ): Temporarily stops delivery of messages; delivery can be restarted with start() .
  • close() (inherited from Connection ): 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 a QueueSender object to send messages to the specified Queue .
  • createReceiver(Queue) : Returns a QueueReceiver object to receive messages from the specified Queue .
  • createBrowser(Queue) (inherited from Session ): Returns a QueueBrowser object to browse messages on the specified Queue .
  • commit() (inherited from Session ): Commits all consumed or produced messages for the current transaction.
  • rollback() (inherited from Session ): Rolls back all consumed or produced messages for the current transaction.
  • create<MessageType>Message(...) (inherited from Session ): 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 indicated Message .
  • setDeliveryMode(int) (inherited from MessageProducer ): Sets the delivery mode for subsequent messages sent; valid values are DeliveryMode.PERSISTENT and DeliveryMode.NON_PERSISTENT .
  • setPriority(int) (inherited from MessageProducer ): Sets the priority for subsequent messages sent; valid values are 0 through 9.
  • setTimeToLive(long) (inherited from MessageProducer ): 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 from MessageConsumer ): Returns the next message that arrives; this method blocks until a message is available.
  • receive(long) (inherited from MessageConsumer ): Receives the next message that arrives within long milliseconds; this method returns null if no message arrives within the time limit.
  • receiveNoWait (inherited from MessageConsumer ): Receives the next message if one is immediately available; this method returns null if no message is available.
  • setMessageListener(MessageListener) (inherited from MessageConsumer ): Sets the MessageListener ; the MessageListener object receives messages as they arrive, that is, asynchronously (see MessageListener ).

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 the MessageListener 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 a TopicSession object. The boolean parameter indicates whether the TopicSession is transacted; the int indicates the acknowledgment mode (see Acknowledgment ).
  • start() (inherited from Connection ): Activates the delivery of messages from the provider.
  • stop() (inherited from Connection ): Temporarily stops delivery of messages; delivery can be restarted with start() .
  • close() (inherited from Connection ): 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 a TopicPublisher object to send messages to the specified Topic .
  • createSubscriber(Topic) : Returns a TopicSubscriber object to receive messages from the specified Topic . 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 a TopicSubscriber object to receive messages from the specified Topic , giving the String 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 the String name.
  • commit() (inherited from Session ): Commits all consumed or produced messages for the current transaction.
  • rollback() (inherited from Session ): Rolls back all consumed or produced messages for the current transaction.
  • create<MessageType>Message(...) (inherited from Session ): A variety of methods that return a <MessageType>Message , such as MapMessage , 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 indicated Message .
  • setDeliveryMode(int) (inherited from MessageProducer ): Sets the delivery mode for subsequent messages sent; valid values are DeliveryMode.PERSISTENT and DeliveryMode.NON_PERSISTENT .
  • setPriority(int) (inherited from MessageProducer ): Sets the priority for subsequent messages sent; valid values are 0 through 9.
  • setTimeToLive(long) (inherited from MessageProducer ): 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 from MessageConsumer ): Returns the next message that arrives; this method blocks until a message is available.
  • receive(long) (inherited from MessageConsumer ): Receives the next message that arrives within long milliseconds; this method returns null if no message arrives within the time limit.
  • receiveNoWait (inherited from MessageConsumer ): Receives the next message if one is immediately available; this method returns null if no message is available.
  • setMessageListener(MessageListener) (inherited from MessageConsumer ): Sets the MessageListener ; the MessageListener object receives messages as they arrive, that is, asynchronously (see MessageListener ).

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值