JMS详解

来源:互联网 发布:久米田康治 知乎 编辑:程序博客网 时间:2024/05/17 01:48
什么是JMS
 

它是Java 消息服务

    Java 消息服务是 J2EE (Java 2 Enterprise Edition) 套件的一部分,它提供了标准 API,Java 开发人员可以使用这些 API 来访问企业消息系统的共同特性。JMS 支持发布/订阅和点对点模型,并允许创建由任意 Java 对象组成的消息类型。

体系架构  

JMS有以下元素组成。

  JMS提供者

  连接面向消息中间件的,JMS接口的一个实现。提供者可以是Java平台的JMS实现,也可以是非Java平台的面向消息中间件的适配器。

  JMS客户

  生产或消费消息的基于Java的应用程序或对象。

  JMS生产者

  创建并发送消息的JMS客户。

  JMS消费者

  接收消息的JMS客户。

  JMS消息

  包括可以在JMS客户之间传递的数据的对象

  JMS队列

  一个容纳那些被发送的等待阅读的消息的区域。队列暗示,这些消息将按照顺序发送。一旦一个消息被阅读,该消息将被从队列中移走。

  JMS主题

  一种支持发送消息给多个订阅者的机制。

JMS模型  

Java消息服务应用程序结构支持两种模型:

  点对点或队列模型

  发布者/订阅者模型

  在点对点或队列模型下,一个生产者向一个特定的队列发布消息,一个消费者从该队列中读取消息。这里,生产者知道消费者的队列,并直接将消息发送到消费者的队列。这种模式被概括为:

  只有一个消费者将获得消息

  生产者不需要在接收者消费该消息期间处于运行状态,接收者也同样不需要在消息发送时处于运行状态。

  每一个成功处理的消息都由接收者签收

  发布者/订阅者模型支持向一个特定的消息主题发布消息。0或多个订阅者可能对接收来自特定消息主题的消息感兴趣。在这种模型下,发布者和订阅者彼此不知道对方。这种模式好比是匿名公告板。这种模式被概括为:

  多个消费者可以获得消息

  在发布者和订阅者之间存在时间依赖性。发布者需要建立一个订阅(subscription),以便客户能够购订阅。订阅者必须保持持续的活动状态以接收消息,除非订阅者建立了持久的订阅。在那种情况下,在订阅者未连接时发布的消息将在订阅者重新连接时重新发布。

  使用Java语言,JMS提供了将应用与提供数据的传输层相分离的方式。同一组Java类可以通过JNDI中关于提供者的信息,连接不同的JMS提供者。这一组类首先使用一个连接工厂以连接到队列或主题,然后发送或发布消息。在接收端,客户接收或订阅这些消息

传递消息方式  

JMS现在有两种传递消息的方式。标记为NON_PERSISTENT的消息最多投递一次,而标记为PERSISTENT的消息将使用暂存后再转送的机理投递。如果一个JMS服务离线,那么持久性消息不会丢失但是得等到这个服务恢复联机时才会被传递。所以默认的消息传递方式是非持久性的。即使使用非持久性消息可能降低内务和需要的存储器,并且这种传递方式只有当你不需要接收所有的消息时才使用。

  虽然JMS规范并不需要JMS供应商实现消息的优先级路线,但是它需要递送加快的消息优先于普通级别的消息。JMS定义了从0到9的优先级路线级别,0是最低的优先级而9则是最高的。更特殊的是0到4是正常优先级的变化幅度,而5到9是加快的优先级的变化幅度。举例来说: topicPublisher.publish (message, DeliveryMode.PERSISTENT, 8, 10000); //Pub-Sub 或 queueSender.send(message,DeliveryMode.PERSISTENT, 8, 10000);//P2P 这个代码片断,有两种消息模型,映射递送方式是持久的,优先级为加快型,生存周期是10000 (以毫秒度量 )。如果生存周期设置为零,这则消息将永远不会过期。当消息需要时间限制否则将使其无效时,设置生存周期是有用的。

  JMS定义了五种不同的消息正文格式,以及调用的消息类型,允许你发送并接收以一些不同形式的数据,提供现有消息格式的一些级别的兼容性。

  · StreamMessage -- Java原始值的数据流

  · MapMessage--一套名称-值对

  · TextMessage--一个字符串对象

  · ObjectMessage--一个序列化的 Java对象

  · BytesMessage--一个未解释字节的数据流

 

JMS应用程序接口

ConnectionFactory 接口(连接工厂)

  用户用来创建到JMS提供者的连接的被管对象。JMS客户通过可移植的接口访问连接,这样当下层的实现改变时,代码不需要进行修改。 管理员在JNDI名字空间中配置连接工厂,这样,JMS客户才能够查找到它们。根据消息类型的不同,用户将使用队列连接工厂,或者主题连接工厂。

Connection 接口(连接)

  连接代表了应用程序和消息服务器之间的通信链路。在获得了连接工厂后,就可以创建一个与JMS提供者的连接。根据不同的连接类型,连接允许用户创建会话,以发送和接收队列和主题到目标。

Destination 接口(目标)

  目标是一个包装了消息目标标识符的被管对象,消息目标是指消息发布和接收的地点,或者是队列,或者是主题。JMS管理员创建这些对象,然后用户通过JNDI发现它们。和连接工厂一样,管理员可以创建两种类型的目标,点对点模型的队列,以及发布者/订阅者模型的主题。

MessageConsumer 接口(消息消费者)

  由会话创建的对象,用于接收发送到目标的消息。消费者可以同步地(阻塞模式),或异步(非阻塞)接收队列和主题类型的消息。

MessageProducer 接口(消息生产者)

  由会话创建的对象,用于发送消息到目标。用户可以创建某个目标的发送者,也可以创建一个通用的发送者,在发送消息时指定目标。

Message 接口(消息)

  是在消费者和生产者之间传送的对象,也就是说从一个应用程序创送到另一个应用程序。一个消息有三个主要部分:

  消息头(必须):包含用于识别和为消息寻找路由的操作设置。

  一组消息属性(可选):包含额外的属性,支持其他提供者和用户的兼容。可以创建定制的字段和过滤器(消息选择器)。

  一个消息体(可选):允许用户创建五种类型的消息(文本消息,映射消息,字节消息,流消息和对象消息)。

  消息接口非常灵活,并提供了许多方式来定制消息的内容。

Session 接口(会话)

  表示一个单线程的上下文,用于发送和接收消息。由于会话是单线程的,所以消息是连续的,就是说消息是按照发送的顺序一个一个接收的。会话的好处是它支持事务。如果用户选择了事务支持,会话上下文将保存一组消息,直到事务被提交才发送这些消息。在提交事务之前,用户可以使用回滚操作取消这些消息。一个会话允许用户创建消息生产者来发送消息,创建消息消费者来接收消息。

 

设计目标

     JMS 的基本设计目标是为了提供一组一致的接口,消息传递系统客户端可以独立地使用这些接口,而不必关心基础消息系统的提供商。这样,客户端应用程序不仅可以跨计算机体系结构和操作系统进行移植,而且也可以跨消息传递产品进行移植。写到 JMS 的客户端应用程序将正常工作,而不用在所有符合 JMS 的消息传递系统上做修改(这可以与组件所运行的基础中间件上的 Enterprise Java Beans 组件的独立性进行比较)。

JMS 也设计成:

     最小化消息传递系统提供商为其产品实现 JMS API 所需的工作量。

     提供了普通消息传递系统的大多数功能。

许多消息系统提供商已经为它们的产品实现了 JMS,允许 Java 访问它们系统的功能。

JMS 客户端可以使用 Java 设施

     由于 JMS 客户端是基于 Java 的,因此它们可以利用现有的 Java API,比如:用于数据库访问

的JDBC、JavaBeans 组件模型、用于命名服务的 JNDI、用于客户端事务控制的 JTA 或用于企业应用程序

服务的任何 J2SE 和 J2EE API。

JMS 细节

什么是消息?

    在消息传递系统中,应用程序之间的通信点是消息本身,因此使用 JMS 的开发人员必须理解消息。

尽管消息传递系统之间消息定义区别甚大,但 JMS 提供了统一的方式用于描述和访问消息。JMS 消息由三部分组成:

消息标题 :用于消息标识。例如,标题用于确定指定的消息是否适合于“订阅者”。

属性 :用于特定于应用程序、特定于提供商及可选的标题字段。

消息体 :保存消息的内容。支持几种格式,其中包括:TextMessages——用于包装简单的 String; 和 ObjectMessages——用于包装任意的 Java 对象(它们必须是可序列化的)。也支持其他的格式。

TextMessages

    TextMessage 用于包装简单的 String 对象。在只传递字符串的情形下,这是有用的。期望许多消息传递系统将以 XML 为基础,TextMessages 是它们的自然容器。

    创建 TextMessage 对象是简单的,如下面两行代码所指出的那样:

TextMessage message =

session.createMessage();

message.setText("hello world");

以这种方式创建的 TextMessage 准备发布到消息传递系统中。

ObjectMessages

    顾名思义,ObjectMessage 是包装了 Java 对象的消息。任何可序列化的 Java 对象均可用作 ObjectMessage。如果多个对象必须在单个消息中传输,那么可以使用包含几个可序列化对象的 Collection 对象(比如 List 或 Set)。

   下面展示了如何创建 Object 消息:

ObjectMessage message = session.createObjectMessage();

message.setObject(myObject);

构建 JMS 客户端

   可以遵循下面的基本步骤来构建典型的 JMS 客户端:

创建到消息传递系统提供商的连接。

创建会话用于发送和接收消息。

创建 MessageProducers 和 MessageConsumers 来创建或接收消息。

    一旦这些步骤执行完毕,消息生产的客户端将创建消息,并把它们发布到主题,而消息消费的客户端将侦听与主题有关的消息,并在它们到达时消费它们。

   为了详细展示它是如何工作的,我们研究了典型的消息生产者,它用于在 pub/sub 消息传递系统中把消息发布到特定的主题。注意,为简洁起见,省略了所有异常处理代码。

创建连接

   连接为客户端提供了对基础消息传递系统的访问,并执行资源分配和管理。连接是使用 ConnectionFactory 创建的,而 ConnectionFactory 通常是使用 JNDI 查找的。

   下面这些代码展示了创建连接过程中涉及的一些步骤:

Context messaging = new InitialContext();

// get JNDI context

TopicConnectionFactory topicConnectionFactory =

(TopicConnectionFactory)

messaging.lookup("TopicConnectionFactory");

TopicConnection topicConnection =

topicConnectionFactory.createTopicConnection();

 

创建会话

    会话是轻量级 JMS 对象,它提供了用于生产和消费消息的上下文。会话用于生成消息生产者和消息消费者,以及用于生成消息本身。

TopicSession session =

topicConnection.createTopicSession(false,

Session.CLIENT_ACKNOWLEDGE);

createTopicSession() 的两个参数控制事务和消息的确认。

查找主题

    主题(也称标题、组或频道)是通过 JNDI 来查找的。主题标识了发送中或接收中的消息。在发布/阅系统中,订阅者订阅了指定的主题,而发布者把主题与它们发布的消息关联。

这里我们创建了一个称为“WeatherData”的主题。

Topic weatherTopic = messaging.lookup("WeatherData");

启动连接

    在上面的初始化过程中,为了防止初始化期间出现不可预知的行为,消息流是被禁止的。一旦初始化完成,必须告诉连接开始消息流。

topicConnection.start();

创建消息生产者

    在发布/订阅领域中,生产者把消息发布到指定主题。下面代码展示了发布者的创建及后续的简单文本消息的生成和发布。

TopicPublisher publisher =

session.createPublisher(weatherData);

TextMessage message = session.createMessage();

message.setText("temperature: 35 degrees");

publisher.publish(message);

 

创建订阅者及点对点系统的 JMS 客户端遵循相似的过程。可以在 [1] 中找到这一过程的完整细节。

结束语

我们已经看到在使用 JMS 来构建基于消息传递的应用程序的过程中涉及的基本概念。在编写 JMS 代码之前,你将需要访问符合 JMS 的消息传递系统。

-----------------------------------------------------------------------

MessageDrivenBean 在 EJB 2.0 中,对规范的一个基础性更改是添加了一种全新的企业级 bean 类型,即 MessageDrivenBean。MessageDrivenBean 专门设计来处理入网的 JMS 消息。对于许多开发人员来说,JMS 是一种新的范例,所以本文将花一些时间逐步说明对 JMS 的理解,以及它们在 EJB 2.0 中的用法。 

JMS 是一种与厂商无关的 API,用来访问消息收发系统。它类似于 JDBC (Java Database Connectivity):这里,JDBC 是可以用来访问许多不同关系数据库的 API,而 JMS 则提供同样与厂商无关的访问方法,以访问消息收发服务。许多厂商目前都支持 JMS,包括 IBM 的 MQSeries、BEA 的 Weblogic JMS service 和 Progress 的 SonicMQ,这只是几个例子。

JMS 使您能够通过消息收发服务(有时称为消息中介程序或路由器)从一个 JMS 客户机向另一个 JML 客户机发送消息。消息是 JMS 中的一种类型对象,由两部分组成:报头和消息主体。报头由路由信息以及有关该消息的元数据组成。消息主体则携带着应用程序的数据或有效负载。根据有效负载的类型来划分,可以将消息分为几种类型,它们分别携带:简单文本 (TextMessage)、可序列化的对象 (ObjectMessage)、属性集合 (MapMessage)、字节流 (BytesMessage)、原始值流 (StreamMessage),还有无有效负载的消息 (Message)。

消息收发系统是异步的,也就是说,JMS 客户机可以发送消息而不必等待回应。比较可知,这完全不同于基于 RPC 的(基于远程过程的)系统,如 EJB 1.1、CORBA 和 Java RMI 的引用实现。在 RPC 中,客户机调用服务器上某个分布式对象的一个方法。在方法调用返回之前,该客户机被阻塞;该客户机在可以执行下一条指令之前,必须等待方法调用结束。在 JMS 中,客户机将消息发送给一个虚拟通道(主题或队列),而其它 JMS 客户机则预订或监听这个虚拟通道。当 JMS 客户机发送消息时,它并不等待回应。它执行发送操作,然后继续执行下一条指令。消息可能最终转发到一个或许多个客户机,这些客户机都不需要作出回应。

EJB 2.0 中的 JMS EJB 2.0 以两种方式支持 JMS 的集成:作为一种 bean 可用的资源,和作为一个 MessageDrivenBean。当将 JMS 用作一种资源时,使用 JMS API 的 bean 就是消息的产生者或发送者。在这种情况下,bean 将消息发送给称为主题或队列的虚拟通道。另一方面,MessageDrivenBean 则是消息的使用者或接收者。它监听特定的虚拟通道(主题或队列),并处理发送给该通道的消息。为了更好地理解消息产生者和消息使用者的作用,用 SessionBean bean 来发送一条使用 JMS 的消息,然后使用一个新的 MessageDrivenBean 来使用该同一条消息。

作为 EJB 2.0 资源的 JMS 会话 bean 和实体 bean 都是基于 RPC 的组件,为了将各种事务性的组件装配到一起,这是一种卓越的体系结构。但是,在某些情况下,RPC 的同步性质会成为一种障碍,这正是 EJB 1.1 中将对 JMS API 的访问作为一种资源包括在内的原因。利用 JNDI 环境命名的上下文,bean 可以获得一个 JMS 工厂,并将一条异步消息发送给主题或队列(也从 JNDI 获得),而不必等待回应。下面是 ShoppingCart bean 的一个例子,它使用 JMS 将 Order 的详细信息发送给消息收发主题

消息中间件

消息中间件提供企业数据的异步传输,通过消息中间件,一些原本互相孤立的业务组件可以组合成一个可靠的、灵活的系统。

消息中间件大致分为两类

Point-to-Point(PTP)

Publish-Subscribe(Pub/Sub)

PTP是点对点传输消息,建立在消息队列的基础上,每个客户端对应一个消息队列,客户端发送消息到对方的消息队列中,从自己的消息队列读取消息。 Pub/Sub是将消息定位到某个层次结构栏目的节点上,Pub/Sub通常是匿名的并能够动态发布消息,Pub/Sub必须保证某个节点的所有发布者(Publisher)发布的信息准区无误地发送到这个节点的所有消息订阅者(Subscriber)。 


JMS定义了Java中访问消息中间件的接口。

JMS只是接口,并没有给予实现,实现JMS接口的消息中间件叫JMS Provider,这样的消息中间件可以从Java里通过JMS接口进行调用。

JMS和其他企业级Java API的关系

JDBC JMS客户端可以使用JDBC接口,可以将JDBC和JMS包含在一个事务里。这种包含可以在EJB里,也可以直接调用JTA(Java Transaction API)接口实现。

JavaBeans JavaBeans可以用JMS Session发送接收消息。

EJB

对于EJB组件来说,JMS和JDBC一样,是一个很重要的企业级服务资源。目前的EJB规范定义客户端只能同步调用EJB,未来的规范将会定义通过一个JMS客户端发消息异步调用EJB组件。

JTA(Java Transaction API) JMS客户端可以用JTA启动事务。JMS Provider可以选择是否支持分布式事务。

JTS(Java Transaction Service) JMS可以和JTS一起组成一个分布式事务,如将发送接收消息和更新数据库包含在一个事务里。

JNDI JMS 客户端通过JNDI调用JMS中的对象。

JMS 消息模型

JMS消息由两部分构成:header和body。header包含消息的识别信息和路由信息,body包含消息的实际数据。

根据数据格式,JMS消息可分为以下五种

BytesMessage 消息是字节流。

MapMessage 消息是一系列的命名和值的对应组合。

ObjectMessage 消息是一个流化的Java对象。

StreamMessage 消息是Java中的输入输出流。

TextMessage 消息是一个字符串,这种类型将会广泛用于XML格式的数据。

JMS 消息优先级

邮局发信分为平信和特快专递两种,同样JMS也根据消息的轻重缓急将消息分为0-9十个级别。0-4是普通消息,5-9是加急消息。JMS不要求消息中间件严格按照这十个优先级发送消息,但必须保证加急消息要先于普通消息到达。

Apusic对JMS的支持

Apusic Application Server包含一个完全遵循JMS接口规范开发的消息中间件,Apusic消息中间件支持通常的两种消息中间件:PTP和Pub/Sub。

原创粉丝点击