为了帮助你理解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等。使用异步可靠消息队列的中间件的,例如IBMWebSphereMQ,SonicMQ,TIBCORendezvous,andApacheActiveMQ,它们都可用在企业消息集成。最后一个要讨论的是消息传送中间件。那么什么是面向消息的中间件?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年发布的,对一些必要的东西进行了改进。JMS1.1版本整合了两种不同的消息传送领域提供了不同的API,所以现在在不同领域的工作也都使用相同的API。这是API的一个巨大的改变。不过,旧的API仍然会被支持。为了规范API,JMS为消息传送定义了很多概念:JMS客户端----100%用Java编写的发送和接收消息的应用。Non-JMS客户端----使用JMS提供者特定的客户端API而不是JMSAPI来发送和接收消息的应用。JMSproducer----创建和发送JMS消息的客户端应用。JMSconsumer----接收和处理JMS消息的客户端应用。JMSprovider----100%使用Java编写的JMS接口的实现。JMSmessage----JMS最基础的概念;被JMS客户端发送和接收。JMSdomains----两者类型的消息传送,包括点对点(point-to-point)和发布/订阅(publish/subscribe)模式。Administeredobjects----预配置的JMS对象,包含provider特定的配置信息。客户端通过JNDI来访问这些数据。Connectionfactory----客户端使用连接工厂来连接JMSprovider。Destination----消息被投递的地方,以及接收者消息接收的来源。除此之外,还有其它一些同样重要的概念。下一部分将深入这些概念并描述它们怎么构建整个JMS。2.4JMS规范就像前面提到的,JMS规范定义了两种客户端--JMS客户端和非JMS客户端。它们之间的区别必须简单讨论下。2.4.1JMS客户端JMS客户端使用JMSAPI与JMS提供者交互。就像使用JDBCAPI去访问关系数据库一样,JMS客户端使用JMSAPI作为消息驱动服务的标准访问方式。许多JMS提供者(包括ActiveMQ)包含了很多超出JMS规范要求的特性。值得一提的是一个100%JMS客户端只能使用JMS提供的API,必须避免使用额外的特性。不过一般选择哪个JMSprovider通常是由它提供的额外特性决定的。所以,一个使用了额外特性的JMS客户端,如果不重构,可能就不能用于其它JMSprovider。JMSclients使用MessageProducer(消息生产者)和MessageConsumer(消息消费者)接口。JMSprovider必须提供这些接口的实现。JMSclient如果发送消息,那么它就是producer(生产者),如果接收消息,那么它就是Consumer(消费者)。JMSclient也有可能同时发送和接收消息。JMSPRODUCERSJMSclients使用JMSMessageProducer类来发送消息到一个destination。当调用Session.createProducer产生一个producer时,将会有默认的destination。不过这个可以通过重写MessageProducer.send()方法来改变。MessageProducer接口如下所示。Listing2.1TheMessageProducerinterfacepublicinterfaceMessageProducer{voidsetDisableMessageID(booleanvalue)throwsJMSException;booleangetDisableMessageID()throwsJMSException;voidsetDisableMessageTimestamp(booleanvalue)throwsJMSException;booleangetDisableMessageTimestamp()throwsJMSException;voidsetDeliveryMode(intdeliveryMode)throwsJMSException;intgetDeliveryMode()throwsJMSException;voidsetPriority(intdefaultPriority)throwsJMSException;intgetPriority()throwsJMSException;voidsetTimeToLive(longtimeToLive)throwsJMSException;longgetTimeToLive()throwsJMSException;DestinationgetDestination()throwsJMSException;voidclose()throwsJMSException;voidsend(Messagemessage)throwsJMSException;voidsend(Messagemessage,intdeliveryMode,intpriority,longtimeToLive)throwsJMSException;voidsend(Destinationdestination,Messagemessage)throwsJMSException;voidsend(Destinationdestination,Messagemessage,intdeliveryMode,intpriority,longtimeToLive)throwsJMSException;}MessageProducer提供了发送消息的和设置消息头部的方法。消息头部设置包括JMSDeliveryMode(投递类型),JMSPriority(优先级),JMSExpiration(有效期,通过get/setTimeLive()设置)以及一个同时设置前面三种消息头的方法send()。这些消息头部将在2.4.5讲解。JMSCONSUMERSJMS客户端使用JM