![[计算机软件及应用]理解面向消息中间件及JMS以及ActieMQ例子.doc_第1页](http://file.renrendoc.com/FileRoot1/2019-1/5/87cc0385-f244-413f-a00b-3f3fa3f80973/87cc0385-f244-413f-a00b-3f3fa3f809731.gif)
![[计算机软件及应用]理解面向消息中间件及JMS以及ActieMQ例子.doc_第2页](http://file.renrendoc.com/FileRoot1/2019-1/5/87cc0385-f244-413f-a00b-3f3fa3f80973/87cc0385-f244-413f-a00b-3f3fa3f809732.gif)
![[计算机软件及应用]理解面向消息中间件及JMS以及ActieMQ例子.doc_第3页](http://file.renrendoc.com/FileRoot1/2019-1/5/87cc0385-f244-413f-a00b-3f3fa3f80973/87cc0385-f244-413f-a00b-3f3fa3f809733.gif)
![[计算机软件及应用]理解面向消息中间件及JMS以及ActieMQ例子.doc_第4页](http://file.renrendoc.com/FileRoot1/2019-1/5/87cc0385-f244-413f-a00b-3f3fa3f80973/87cc0385-f244-413f-a00b-3f3fa3f809734.gif)
![[计算机软件及应用]理解面向消息中间件及JMS以及ActieMQ例子.doc_第5页](http://file.renrendoc.com/FileRoot1/2019-1/5/87cc0385-f244-413f-a00b-3f3fa3f80973/87cc0385-f244-413f-a00b-3f3fa3f809735.gif)
已阅读5页,还剩30页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
为了帮助你理解ActiveMQ的意义,了解企业消息传送背景和历史是很重要的。讨论完企业消息传送,你将可以通过一个小例子了解JMS及其使用。这章的目的是简要回顾企业消息传送及JMS规范。如果你已经熟悉这些主题,你可以跳过直接到下一章去。 软件开发者经常需要在两个系统之间交流或搬运数据。这种问题有很多解决办法。但限于你的条件和需求,选择一种解决方案是一个大决定。商业需求往往有严格的限制条件,直接影响你的决定的有性能,扩展性,稳定性等。我们日常使用的很多系统都有这样的要求,比如ATM系统,航班预订系统,信用卡系统,单点销售系统,通信系统等。如果我们的日常生活没有这些系统会怎样?用一小会的时间想一下这些服务给我们的生活带来了怎样的便利。这些及其它类似应用能够方便我们的生活在于他们的稳定和安全性。在这些应用场景背后,是很多应用组合起来的,通常是分布式的,它们之间相互传递事件或消息。即使是最复杂的金融交易系统也是用这种方式集成的,完全通过消息传送来发送和接收商业信息。由于各种各样的理由,很多产品都提供消息传送。必要性是发明之母,这就是消息中间件产生的原因。当时需要一种软件,能够在各种不同的数据类型,操作系统,协议甚至是不同的编程语言中交流数据。并且,复杂的消息路由和转移也成为这种解决方案的一部分必备能力。ActiveMQ就是一个MOM产品,它为上面提到的商业系统提供异步消息传送。ActiveMQ通过实现JMS规范提供了这样一种可靠性和扩展性。2.1介绍企业消息传送 向上面提及的大多数系统是由许多大型的计算机一起构建的,并且到今天仍然在使用。那么,这些系统怎么可靠地运作呢?要回答这个问题,我们先简要回顾下这种解决方案的历史及企业消息传送是怎么产生的。 从上世纪60年代开始,许多大型的组织使用大型机来处理一些诸如数据处理,财务处理,静态分析等关键功能。大型机为商业提供包括高可用性,冗余备份,可靠性,可扩展性,无中断升级等许多关键特性。虽然这些系统很强大,但是对这些系统的访问时被严格控制的,只有很少的输入选择。而且,系统间的内部联系还没有发明,也就是说并发处理是不可能的。图2.1展示了终端设备是如何连接上大型机的。在19世纪70年代,人们开始使用终端连接到大型机。这种方式使得大量的使用者可以同时访问一个大型机。也就在这时,网络产生了,大型机之间的交互成为可能。到了80年代,不只是有了图形界面的终端,PC机也被发明了。互联性也越来越重要,因为本来需要连接到大型机上的应用已经被开发到可以在PC和工作站上运行。图2.2展示了对大型机的各种类型的连接。这些扩展到连接带来了额外的平台和协议,同时也带来了很多需要解决的问题。连接两个系统并不是一件简单的事,因为它们的数据格式,硬件,协议都需要不同的适配器。但适配器数量增长,版本也随之增多,维护非常困难。所以需要将适配器的维护独立于各系统。这也就是企业消息传送的用途。企业消息传送到目的就是在系统间传递数据。这些年来已经有各种不同的技术可以进行消息传送,如下列表所示。 通过远程过程调用(RPC)的解决方案,例如COM,CORBA,DCE及EJB 使用事件通知,内部交互,消息队列的,例如FIFO缓冲,消息队列,管道,信号,socket等。 使用异步可靠消息队列的中间件的,例如IBM WebSphere MQ, SonicMQ, TIBCO Rendezvous,and Apache ActiveMQ,它们都可用在企业消息集成。 最后一个要讨论的是消息传送中间件。那么什么是面向消息的中间件?2.2什么是面向消息中间件 面向消息中间件(MOM)为分布式系统提供异步,解耦,稳定,可扩展和安全的行为。MOM在分布式计算领域是一个重要的概念。它允许应用使用代理器API在分布式环境实现各种功能。总之,MOM的设计原理就是作为消息发送者和接收者的中间人使用。这个中间人提供了一个高级别的解耦。图2.3演示了ActiveMQ作为中间人,不只是可以联系应用和大型机,还可以实现应用间的交互。在一个较高级别看,消息就是一个商业信息单元,它通过MOM从一个应用发送到另一个应用。应用使用目标(destinations)来发送和接收消息。消息将被投递到destinations,然后发送给连接或订阅该destinations的接收者。这个机制能够解耦消息的发送者和接收者,因为它们在发送或接收消息的时候并不需要同时连接ActiveMQ。发送者不了解接收者,接收者也不了解发送者。这个机制就叫做异步消息传送。MOMs添加了很多原来紧耦合系统不可能实现的特性,例如消息持久化,对于缓慢和不稳定连接的健壮性,复杂消息路由,消息转移等。消息持久化能减轻缓慢或不稳定连接,或者使得接收者接收消息失败时不会影响发送者的状态。复杂的消息路由使很多东西都成为可能,包括单一消息对应多个接收者,通过属性或者内容选择路由等。消息转移允许拥有不同消息格式的两个应用通过自定义的消息格式进行交流。目前市场上的MOMs提供一系列预制的连接协议。被支持的协议一般有HTTP/S,multicast,SSL。TCP/IP,UDP等。一些提供商甚至提供多种编程语言支持,这大大降低了在不同环境下使用MOMs的难度。ActiveMQ提供上述所有的特性,而且更多。一般地,MOM会提供一些API来发送,接收消息及和MOM交互。多年来,MOM提供商为它们选择的语言提供专有的API。直到JMS规范到来才改变这种情况。2.3什么是Java消息服务 JMS是在MOM供应商核心API基础上发展的,它用来提供企业消息传送。JMS的目标是为Java提供一个标准的API来发送和接收消息,并使之成为供应商天生行为。JMS最小化了Java程序员开发企业消息应用的复杂性,同时还保留在不同JMS提供者之间移植的可能性。JMS并不是一个MOM。它是一个API,抽象了客户端和MOM的交互,就像JDBC抽象与数据库的交互一样。图2.4展示了客户端是如何通过JMS提供的API和特定JMS提供者交互。特定的JMS提供者使用供应商制定的API和MOM交互。不只是图示的四种,对于其它JMS提供者也是相同的。为了联合企业消息传送市场上的各厂商,Sun在1998年颁布了JMS规范的第一个版本。最后一个版本是2002年发布的,对一些必要的东西进行了改进。JMS 1.1版本整合了两种不同的消息传送领域提供了不同的API,所以现在在不同领域的工作也都使用相同的API。这是API的一个巨大的改变。不过,旧的API仍然会被支持。为了规范API,JMS为消息传送定义了很多概念: JMS客户端-100%用Java编写的发送和接收消息的应用。 Non-JMS客户端-使用JMS提供者特定的客户端API而不是JMS API来发送和接收消息的应用。 JMS producer-创建和发送JMS消息的客户端应用。 JMS consumer-接收和处理JMS消息的客户端应用。 JMS provider-100%使用Java编写的JMS接口的实现。 JMS message-JMS最基础的概念;被JMS客户端发送和接收。 JMS domains-两者类型的消息传送,包括点对点(point-to-point)和发布/订阅(publish/subscribe)模式。 Administered objects-预配置的JMS对象,包含provider特定的配置信息。客户端通过JNDI来访问这些数据。 Connection factory-客户端使用连接工厂来连接JMS provider。 Destination-消息被投递的地方,以及接收者消息接收的来源。 除此之外,还有其它一些同样重要的概念。下一部分将深入这些概念并描述它们怎么构建整个JMS。2.4 JMS规范 就像前面提到的,JMS规范定义了两种客户端-JMS客户端和非JMS客户端。它们之间的区别必须简单讨论下。2.4.1 JMS客户端 JMS客户端使用JMS API与JMS提供者交互。就像使用JDBC API去访问关系数据库一样,JMS客户端使用JMS API作为消息驱动服务的标准访问方式。许多JMS提供者(包括ActiveMQ)包含了很多超出JMS规范要求的特性。值得一提的是一个100%JMS客户端只能使用JMS提供的API,必须避免使用额外的特性。不过一般选择哪个JMS provider通常是由它提供的额外特性决定的。所以,一个使用了额外特性的JMS客户端,如果不重构,可能就不能用于其它JMS provider。JMS clients使用MessageProducer(消息生产者)和MessageConsumer(消息消费者)接口。JMS provider必须提供这些接口的实现。JMS client如果发送消息,那么它就是producer(生产者),如果接收消息,那么它就是Consumer(消费者)。JMS client也有可能同时发送和接收消息。JMS PRODUCERS JMS clients使用JMS MessageProducer类来发送消息到一个destination。当调用Session.createProducer产生一个producer时,将会有默认的destination。不过这个可以通过重写MessageProducer.send()方法来改变。MessageProducer接口如下所示。Listing 2.1 The MessageProducer interfacepublic interface MessageProducer void setDisableMessageID(boolean value) throws JMSException;boolean getDisableMessageID() throws JMSException; void setDisableMessageTimestamp(boolean value) throws JMSException;boolean getDisableMessageTimestamp() throws JMSException;void setDeliveryMode(int deliveryMode) throws JMSException;int getDeliveryMode() throws JMSException;void setPriority(int defaultPriority) throws JMSException;int getPriority() throws JMSException;void setTimeToLive(long timeToLive) throws JMSException;long getTimeToLive() throws JMSException;Destination getDestination() throws JMSException;void close() throws JMSException;void send(Message message) throws JMSException;void send(Message message, int deliveryMode, int priority,long timeToLive)throws JMSException;void send(Destination destination, Message message)throws JMSException;void send(Destination destination,Message message,int deliveryMode,int priority,long timeToLive)throws JMSException;MessageProducer提供了发送消息的和设置消息头部的方法。消息头部设置包括JMSDeliveryMode(投递类型),JMSPriority(优先级),JMSExpiration(有效期,通过get/setTimeLive()设置)以及一个同时设置前面三种消息头的方法send()。这些消息头部将在2.4.5讲解。JMS CONSUMERS JMS客户端使用JMS MessageConsumer类从一个destionation消费消息。它可以通过receive()方法同步地消费消息,也可以通过提供一个MessageListener实现来异步地消费消息。MessageListener.onMessage()方法会在消息到达destination时被调用。MessageConsumer接口如下所示。Listing 2.2 The JMS MessageConsumer interfacepublic interface MessageConsumer String getMessageSelector() throws JMSException;MessageListener getMessageListener() throws JMSException;void setMessageListener(MessageListener listener) throws JMSException;Message receive() throws JMSException;Message receive(long timeout) throws JMSException;Message receiveNoWait() throws JMSException;void close() throws JMSException;接口中没有方法为MessageConsumer设置destination。事实上,destination会在使用Session.createConsumer()创建Consumer的时候被设置。2.4.2 Non-JMS clients 就像先前提到的Non-JMS客户端使用JMS provider本地的客户端API,而不是使用JMS API。这是个重要的区别,因为本地的客户端API可能提供一些不同的特性。这类本地non-JMS API能够在Java RMI上面使用CORBA IIOP协议或其它一些本地协议。在JMS规范出来之前的一些消息provider通常有本地的客户端API,之后,也有很多JMS provider提供本地的API。2.4.3 The JMS provider JMS provider是一个由供应商提供的JMS API实现。它们提供标准的JMS API来访问MOM。(这和JDBC类似)2.4.4 The JMS message JMS消息是JMS规范最重要的一个概念。JMS规范所有其它概念都是围绕消息处理而建立的,因为消息是商业数据和事件的载体。JMS消息能够传输任何的数据,包括文本,二进制数和以及在消息头的信息等。如何2.5,JMS消息包含两部分,包括消息头和负载(payload)。消息头为客户端和JMS provider提供消息的元数据。payload事实上就是消息体,可以通过各种消息类型,存放文本和二进制数据。JMS消息被设计为容易理解和变通。所有复杂的东西都留在消息头部。2.4.5 JMS消息内部 就像上面提到的,JMS消息复杂部分在它的头部。有两种头部,它们都是基于相同的逻辑概念,但是有很大的不同。除了一系列标准的头部和方法,还有properties方法。poperties是基于Java类型,用来处理自定义头部。JMS消息头部 如图2.5所示,JMS消息支持一系列标准的消息头部,并且为之提供JMS API。很多头部会自动被赋值。接下来将描述这些头部,并看看它们 是怎么被赋值。通过send()方法自动被赋值的头部: JMSDestination-消息被发送到的目的地。这个对于从多个目标中接收消息的客户端有用。 JMSDeliveryMode-JMS支持两种消息发送模式:持久化和非持久化。默认是持久化的消息。不同的模式有不同的负载,也提供不同级别的可靠性。 持久的(Persistent)-让JMS提供者持久化消息,所以当provider失败时消息不会丢失。JMS提供者必须投递每个持久化消息一次并且只有一次。也就是说,即使JMS提供者失败,消息不会丢失也不会被投递多于一次。 由于需要存储消息及提高稳定性,所以持久化消息会要求更多的开销。非持久的(Nonpersistent)-让JMS提供者不要持久化消息。JMS对于非持久化消息最多投递一次。也就是说,如果消息投递失败,则会丢失。非持久化消息开销较小,同时稳定性也较差。消息投递模式是设置在生产者上面的,它对该生产者生产的所有消息有效。不过,消息投递模式也可以在单独的发生某个消息时被重写。 JMSExpiration-JMS消息的过期时间。这个头部会阻止发送一条已经过期的消息。有两种方法设置过期时间。一种是通过MessageProducer.setTimeToLive()方法,此方法设置的消息存在时间对所有由该生产者生产的消息有效;一种是通过MessageProducer.send()方法,此方法设置的消息有效时间对本次发送的消息有效。 JMSExpiration头部是通过time-to-live时间加上当前时间计算出来的。默认地,time-to-live时间是零,这意味着消息永远不会过期。如果time-to-live被明确赋值为0,效果也是一样的。这个头部对于时间敏感的消息有用。不过要注意,虽然JMS提供者不会发送过期消息,JMS客户端自己也必须保证不处理过期消息。 JMSMessageID-JMS提供者产生的消息唯一标识,它必须以提供者的id开头。消息id可以用在消息处理,也可以储存下来用于追踪历史信息。由于生成id会给JMS提供者带来一些开销,所以生产者可以通过MessageProducer.setDisableMessageID()方法,告诉JMS提供者,应用不需要JMSMessageID。如果JMS提供者接受请求,则消息ID会被设置为null。不过要注意,JMS也可能忽略该请求,仍然提供MessageID。 JMSPriority-用于指明消息的重要级别。这个也是设置在消息生产者上面的,并且对该生产者生产的所有消息有效。也可以对单独的消息重写这个优先级。JMS定义了0-9十个基本的优先级。 Priorities 0-4 -属于通常级别。Priorities 5-9 -属于加快级别。JMS提供者并没有被要求实现消息顺序,不过大多数都会提供该功能。它们可能简单地先发送高优先级的消息再发送低优先级的消息。 JMSTimestamp-显示消息是何时从生产者发到消息提供者的。这个值使用Java标准毫秒数。就像JMSMessageID一样,生产者也可以建议JMS提供者不用提供这个值。设置的方法是MessageProducer.setDisableMessageTimestamp()。如果JMS提供者接受该建议,则这个值被设置为0. 客户端可选的头部: JMSCorrelationID-用来关联当前消息和之前的消息。最常用在关联一条响应消息和它的请求消息。这个值可以是: * 一个提供者指定的消息ID。* 一个应用指定的字符串。* 一个提供者本地的字节数组由提供者指定的消息ID都会带有ID前缀,所以,应用指定的字符串不应带有ID前缀。如果一个JMS提供者支持本地的correlation ID,那么JMS客户端可能需要对correlation ID赋值以匹配非JMS客户端,不过这个并非强制要求。 JMSReplyTo-用来指定一个响应发生的目标。这个值一般用在请求/响应的消息传送风格中。使用该头部的消息表明它期望得到响应,不过这并非强制要求。由客户端决定是否响应。 JMSType-语义上的消息类型。只有很少供应商使用该头部,而且它和消息的负载类型(持久化/非持久化)无关。 JMS提供者可选头部 JMSRedelivered-用来指出一条消息被投递但没有收到应答的情况。这种情况可能是消费者应答失败,或者JMS提供者没有被通知到(例如异常发生使得应答消息没有到达JMS提供者)。 JMS消息属性 属性是消息的一些简单的额外的头部。JMS提供通用的方法来设置自定义头部。这些通用方法提供对各种Java原始类型的支持,包括Boolean,byte,short,int,long,float,double及String对象。详情请看下面Message接口方法清单:Listing 2.3 The JMS Message interfacepublic interface Message .boolean getBooleanProperty(String name) throws JMSException;byte getByteProperty(String name) throws JMSException;short getShortProperty(String name) throws JMSException;int getIntProperty(String name) throws JMSException;long getLongProperty(String name) throws JMSException;float getFloatProperty(String name) throws JMSException;double getDoubleProperty(String name) throws JMSException;String getStringProperty(String name) throws JMSException;Object getObjectProperty(String name) throws JMSException;.Enumeration getPropertyNames() throws JMSException;boolean propertyExists(String name) throws JMSException;.void setBooleanProperty(String name, boolean value) throws JMSException;void setByteProperty(String name, byte value) throws JMSException;void setShortProperty(String name, short value) throws JMSException;void setIntProperty(String name, int value) throws JMSException;void setLongProperty(String name, long value) throws JMSException;void setFloatProperty(String name, float value) throws JMSException;void setDoubleProperty(String name, double value) throws JMSException;void setStringProperty(String name, String value) throws JMSException;void setObjectProperty(String name, Object value) throws JMSException;. 有两个方法对所有属性有用,它们是getPropertyNames()和propertyExists()方法。getPropertyName()方法返回一个所有属性的Enumeration,这使得客户端可以很容易地遍历所有属性。propertyExists()方法是用来测试一个属性是否存在该消息中。注意这两个方法是对属性有用,那些JMS规范指定的头部(例如MessageID等)是不能用这两个方法来遍历或测试的。总之,现在有三种类型的属性,自定义属性,JMS定义属性,提供者指定属性。自定义属性 自定义属性是任意的,是由JMS应用定义的。应用开发者,可以通过下面的一些通用方法(getBooleanProperty()/setBooleanProperty(), getStringProperty()/setStringProperty()等)来定义各种使用java类型的属性。JMS定义属性 JMS规范保留了“JMSX”作为属性名前缀。下面是一些定义了的属性,这些属性都是可选的。 JMSXAppID-发生消息应用的ID JMSXConsumerTXID-消费这条消息的事务ID JMSXDeliveryCount-消息参与投递的次数 JMSXGroupID-该消息所属的消息组 JMSXGroupSeq-该消息在消息组中所处的序列 JMSXProducerTXID-生产这条消息的事务ID JMSXRcvTimestamp-JMS提供者将消息投递给消费者的时间 JMSXState-用来定义提供者指定的状态 JMSXUserID-发送这条消息的用户 JMS规范只对JMSXGroupID和JMSXGroupSeq这两个属性的用法提供了建议。这两个属性可以用在消息分组/带顺序的消息分组。提供者指定属性 JMS预留了JMS_属性前缀作为提供者指定属性。提供者用这个前缀定义自己的属性。这些属性一般用在提供者指定的非JMS客户端,并且不能用在JMS-to-JMS消息传送中。现在JMS的头部和属性已经讨论完了。头部和属性对于预订了消息的客户端很重要,它可以用来帮助过滤消息。2.4.6消息选择器 很多时候,一个JMS客户端订阅了一个目标,但是它只想接收特定类型的消息。这种情况,消息头部和属性正好派上用场。例如,一个消费者到一个队列注册,希望接收到特定股票的消息。只要该消息包含一个股票标识的属性,那么这个功能就很容易实现。JMS客户端可以用消息选择器告诉JMS提供者它要接收某个属性值符合要求的消息。许多选择器允许JMS客户端基于消息头部的值指定它要接收到消息。选择器使用SQL92子集的条件表达式。消息选择器使用消息头部和属性值来进行布尔计算。不符合的消息将不会投递到客户端。消息选择器不能作用于消息体。条件表达式作为字符串参数传递给javax.jms.Session创建选择器的方法。这些条件表达式使用包括标识符,字面量和操作符等从SQL92语法继承的符号。这些东西都在下面的表2.1中定义。上面的这些东西都是用来对消息头部和属性创建查询条件的。看下面列表定义的消息。这条消息定义了两个属性,它们将被用来过滤消息。Listing 2.4 A JMS message with custom propertiespublic void sendStockMessage(Session session,MessageProducer producer,Destination destination,String payload,String symbol,double price)throws JMSException TextMessage textMessage = session.createTextMessage();textMessage.setText(payload);textMessage.setStringProperty(SYMBOL, symbol);textMessage.setDoubleProperty(PRICE, price);producer.send(destination, textMessage);现在让我们来看一些使用消息选择器的例子。Listing 2.5 Filter messages using the SYMBOL header.String selector = SYMBOL = AAPL;MessageConsumer consumer =session.createConsumer(destination, selector);.列表2.5的程序定义了一个匹配苹果公司消息的选择器。这个消费者只会接收到匹配该选择器的消息。Listing 2.6 Filter messages using both the SYMBOL and PRICE headers.String selector = SYMBOL = AAPL AND PRICE + getPreviousPrice();MessageConsumer consumer =session.createConsumer(destination, selector);.上面的选择器匹配苹果公司并且价格高于之前价格的股票消息。这个选择器将会显示那些价格在上涨的股票消息。但是,如果你对股票消息的时效性有要求,那么可以看看下面的例子。Listing 2.7 Filter messages using headers.String selector = SYMBOL IN (AAPL, CSCO) AND PRICE + getPreviousPrice() + AND PE_RATIO + getCurrentAcceptedPriceToEarningsRatioThreshold();MessageConsumer consumer =session.createConsumer(destination, selector);.最后的例子2.7定义了一个更复杂的选择器。这个选择器可以用来匹配苹果及思科公司那些正在增长的,并且市盈率小于当前可接受值的消息。上面的例子对于你开始使用消息选择器来说已经足够了。但是如果你想要更多的信息,可以参考JMS消息的Javadoc。消息体 消息体,也就是负载,JMS为它定义了六种Java类型。使用这些Java对象,信息就可以通过消息负载发送出去。 Message-基本的消息类型。用来发送没有负载,只有头部和属性的消息。最常用在简单的事件通知。 TextMessage-负载是String类型的消息。用在发送简单文本或XML数据。 MapMessage-使用一系列name/value(名称/值)做为它的负载。名称使用字符串,值是Java原始类型。 BytesMessage-包含一个不能被中断字节数组作为负载。 StreamMessage-包含一些Java原始类型的流,会按顺序被填充和读取。 ObjectMessage-用来包含一个序列号Java对象。一般用来存储复杂Java对象,也支持Java集合。2.4.7 JMS领域 就像之前提到的,JMS是团队成果,这个团队就包括了消息传送实现的提供商。JMS定义了两种类型的消息传送,这是由现有的消息传送实现决定的。这两种风格(也叫做领域domains)是point-to-point及publish/subscribe。大多数的MOMs已经支持两种类型的消息传送风格,所以JMS API也必须同时支持它们。让我们详细看下这两种类型的消息传送。点对点领域 点对点(PTP)消息传送使用的目标是队列。通过使用队列,消息可以被异步或同步地发送和接收。每一条到达队列的消息将会被投递到单独一个消费者一次,并且只有一次。这就好像两个人之间的邮件发送。消费者可以通过MessageConsumer.receive()方法同步地接收消息或使用MessageConsumer.setMessageListener()方法注册一个MessageListener实现来异步地接收消息。队列保存所有的消息直到它们被投递出去或过期。如图2.6所示,多个消费者可以注册在一个队列上,但一条消息只有一个消费者会接收到。然后消费者要决定是否应答这条消息。注意,图2.6所示的消息是从一个生产者出来的并且只投递给一个消费者,而不是所有消费者。就像前面提到的,JMS提供者保证消息一次并且只有一次投递给下一个准备好的消费者。JMS提供者是对所有已注册的消费者循环发送消息的。发布订阅领域 发布订阅模式的消息使用主题(topics)作为目标。发布者发送消息到主题,订阅者从主题接收消息。发送到主题的消息会自动发给所有的订阅者。这个消息传送领域就像预制一个邮件列表,所有邮件列表上的用户都会受到消息。图2.7描述了这种情况。就像PTP消息传送一样,订阅者可以通过MessageConsumer.receive()方法同步地接收消息或使用MessageConsumer.setMessageListener()方法注册一个MessageListener实现来异步地接收消息。主题并不保存消息,除非显式地让它这样做。这个可以通过使用持久订阅(durable subscription)来实现。使用持久订阅,如果一个订阅者与JMS提供者连接断开,JMS提供者有责任为该订阅者保存消息。重新连上后,订阅者将收到所有的未过期的消息。持久订阅允许订阅者断开连接而不会丢失任何消息。持久订阅(durability)和消息持久化(persistence)的区别 持久订阅和消息持久化是JMS经常会混淆的两个概念。虽然它们很类似,但是还是有一些明显的不同,并且它们的用途也不一样。消息持久订阅只在发布/订阅领域有效。当客户端连接到一个主题上,它们可以选择使用持久或非持久订阅。考虑这两种情况的区别。 持久订阅-一个持久订阅的时间是无限的。客户端注册到主题上,并且告诉JMS提供者当订阅者断开连接时保持订阅状态。如果一个订阅者的连接断开了,JMS提供者将保持所有的消息直到订阅者重新连上或者订阅者取消订阅。 非持久订阅-一个非持久订阅是有限的。客户端注册到主题上并且告诉JMS提供者当连接断开是不用保持订阅状态。如果一个订阅者断开连接,JMS提供者在断开的这段时间里不会保存任何消息。 消息持久化是独立于消息领域的。消息持久化是一种服务质量属性,它用来指出JMS应用处理消息投递失败时的能力。就像之前提到的,这个值是通过消息生产者setDeliveryMode方法来设置的,这个方法的输入参数是JMSDeliveryMode类的变量PERSISTENT或NON-PERSISTENT。JMS应用的请求/回复传送机制 虽然JMS规范没有把请求/回复(request/reply)消息传送作为一种正式的消息领域来定义。当它提供了一些消息头部和许多有用的类来处理请求/回复消息传送。请求/回复消息传送是一种异步的会话模式,可以在PTP或pub/sub领域使用。这种模式会用到JMSReplyTo和JMSCorrelationID消息头部及临时的消息目标。JMSReplyTo指定一个回复消息投递的目标,JMSCorrelationID指定回复消息对应的请求的JMSMessageID。这些头部用来关联回复消息和它(们)的请求消息。临时的目标只能在连接持续时间里有效并且只能被创建它的连接使用。这些限制条件使得临时目标对于请求/回复模式很有用。QueueRequestor和TopicRequestor是两个处理请求/回复模式的有用的类。这些类提供一个request()方法发送一条请求消息并且通过临时目标等待回复。一般地,是一个请求预期会得到一个回复。图2.8显示了一个请求,一个回复的流程。图2.8通过两个终端描绘了基本的请求/回复消息传送类型。这个过程是使用了JMSReplyTo消息头部和一个临时目标。接收者通过临时目标发送回复消息,请求者则通过它接收消息。QueueRequestor和TopicRequestor这两个类可以用来处理基本的请求/回复模式,但不能用来处理复杂的情况,比如一个请求对应多个接收者的多个回复。这种需求要求你自己开发自定义的JMS客户端。2.4.8 管理对象(Administered objects) 管理对象包含JMS提供者特定的配置信息,它由JMS管理者创建。因此,管理对象是被JMS客户端使用的。它们用来隐藏提供者特定的细节并且抽象JMS提供者的管理任务。管理对象可以通过JNDI访问,但不是必须。最常见的情况是JMS提供者寄居在Java EE容器里。JMS规范提供两种类型的管理对象:连接工厂(ConnectionFactory)和目标(Destination)。连接工厂 JMS客户端使用连接工厂来创建到JMS提供者的连接。连接一般就是一个客户端与JMS提供者之间的TCP连接,所以连接的负载是很大的。使用一个连接池是比较合适的。一个到JMS提供者的连接就像一个到关系数据库的JDBC连接(JDBC连接是客户端用来和数据库交互的)。客户端使用JMS连接来创建java.jms.Session对象,该对象代表与JMS提供者的一个交互。目标 目标封装了提供者特定的地址,这地址是用来发送和消费信息的。虽然目标是使用session对象创建的,它们的生存时间是和创建session的连接一致。临时目标对于一个连接是唯一的。它们的生命周期和创建它们的连接一致,并且只有创建它们的连接才能为该目标创建消费者。就像前面提到的,临时目标是用在请求/回复消息传送中的。2.5使用JMS API创建JMS应用 因不同的商业要求,创建一个JMS应用可以很简单也可以很复杂。就像JDBC,JNDI,EJBs等API,抽象JMS API,使得JMS代码和商业逻辑相分离是必须的。这个概念不会在这里讨论,因为这要涉及到模式和应用架构,不是一两句话可以说完的。下面是一些简单的例子,它们向你展示了一个最基本的JMS APIs的使用,2.5.1 一个简单的JMS应用 一个JMS应用使用Java语言编写的,它组合了各个部分来和JMS一起工作。这些部分在2.3节已经讨论过。一个简单的JMS应用会下面的步骤:1. 请求一个JMS连接工i厂。 2. 是用连接工厂创建连接。 3. 启动JMS连接。 4. 通过连接创建session。 5. 获取一个目标。 6. 创建一个生产者,或a.创建一个生产者,b.创建一条JMS消息并发送到目标 7. 创建一个消费者,或a.创建一个消费者,b.注册一个消息监听器。 8. 发送或接受消息。 9. 关闭所有资源(连接,会话,生产者,消费者等)。 这些步骤是用来展示使用JMS的一个简单流程。下面的列表用来展现创建一个生产者并发送消息的代码。Listing 2.8 Sending a JMS messagepublic class MyMessageProducer .ConnectionFactory connectionFactory;Connection connection; Session session;Destination destination;MessageProducer producer;Message message;boolean useTransaction = false;try Context ctx = new InitialContext();connectionFactory =(ConnectionFactory) ctx.lookup(ConnectionFactoryName);connection = connectionFactory.createConnection();connection.start();session = connection.createSession(useTransaction,Session.AUTO_ACKNOWLEDGE);destination = session.createQueue(TEST.QUEUE);producer = session.createProducer(destination);message = session.createTextMessage(this is a test);producer.send(message); catch (JMSException jmsEx) . finally producer.close();session.close();connection.close();列表2.8,首先创建了一个上下文。通常情况下,上下文是通过JNDI路径获取的,这个例子只是用来演示的。在初始化的上下文中通过使用连接工厂的唯一名字获取它。通过连接工厂,JMS连接被创建和启动。这之后,JMS客户端可以开始和代理器交互了。通过JMS连接,JMS会话被创建并且使用自动答复消息类型。JMS队列通过会话被创建。接下来是使用会话和目标创建生产者。之后通过会话创建了一条简单的文本消息并由生产者发送出去。最后的一个步骤是关闭所有用到的对象。2.8的例子演示了一个最简单的创建生产者和发送一条消息到目标的动作。注意,有没有一个消费者在
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 科技企业开放日活动计划
- 线上钢琴课程推广计划
- 物业服务交接后续支持与维护计划
- 自助创业协议
- 车险借款协议融资
- 人教版语文教学计划的教师培训需求
- 健身行业质量管理体系年度改进计划
- 物业管理公司网络维护计划
- 小学音体美教研组协作计划
- 教育认证外包协议
- 联合经营合同协议样本
- 雅马哈便携式扩声系统STAGEPAS 600i使用说明书
- 2024年六西格玛黄带认证考试练习题库(含答案)
- 文艺学名著导读学习通超星期末考试答案章节答案2024年
- 子女抚养协议合同模板
- 健康证记录表-自动提示过期功能
- 物理与人类文明学习通超星期末考试答案章节答案2024年
- 地质灾害防治工程勘察规范DB50143-2003
- 商铺用电收费协议书模板
- 考察提拔干部近三年个人工作总结材料
- 2024年同等学力英语考试真题及详解
评论
0/150
提交评论