这一章的内容有:
- ActiveMQ特性和使用总览
- 下载和安装ActiveMQ
- 理解ActiveMQ文件结构
- 运行ActiveMQ自带例子
企业消息软件从80年代起就存在,它不只是一种应用间消息传递风格,也是一种集成风格。因此,消息传递可以满足应用间的通知和互相操作。但是开源的解决方案是到最近10年才出现的。Apache
ActiveMQ就是其中一种。它使应用间能以异步,松耦合方式交流。本章将向您介绍ActiveMQ。
ActiveMQ是Apache软件基金下的一个开源软件,它遵循JMS1.1规范(Java
Message Service),是消息驱动中间件软件(MOM)。它为企业消息传递提供高可用,出色性能,可扩展,稳定和安全保障。ActiveMQ使用Apache许可协议。因此,任何人都可以使用和修改它而不必反馈任何改变。这对于商业上将ActiveMQ用在重要用途的人尤为关键。MOM的工作是在分布式的各应用之间调度事件和消息,使之到达指定的接收者(第二章将阐述该内容)。所以高可用,高性能,高可扩展性尤为关键。
ActiveMQ的目标是在尽可能多的平台和语言上提供一个标准的,消息驱动的应用集成。ActiveMQ实现JMS规范并在此之上提供大量额外的特性。这些额外的特性也会在这本书中详细阐述。
你最初的几步对于你成功将ActiveMQ应用在你的工作中尤为重要。对于新手,ActiveMQ看起来令人恐惧;对于有经验的人,则会比较容易理解。这一章将带你熟悉ActiveMQ。你将了解到ActiveMQ的特性集,也将了解到为什么和在哪里部署ActiveMQ。之后,你将有足够的知识去安装和开始使用ActiveMQ。
1.1 ActiveMQ特性
ActiveMQ提供大量的特性,这些特性是用大量人力进行开发的。本书的各章将专注这些特性的各个部分进行讲解。下面是一个高层次的特性列表。
- 遵循JMS规范 ----理解ActiveMQ的起始点是明白ActiveMQ的各种特性是JMS1.1规范的实现。本章后面将讨论JMS规范提供的好处和保证。它们包括同步和异步消息传递,一次和只有一次的消息传递,对于预订者的持久消息等等。依附于JMS规范意味着,不论JMS消息提供者是谁,同样的基本特性都是有效的。
- 连接----ActiveMQ提供各种连接选择,包括HTTP,HTTPS,IP多点传送,SSL,STOMP,TCP,UDP,XMPP等。大量的连接协议支持使之具有更好的灵活性。很多现有的系统使用一种特定协议并且不能改变,所以一个支持多种协议的消息平台降低了使用的门槛。虽然连接很重要,但是和其他容器集成也同样重要。第四章将讲解ActiveMQ的传输连接器(transport
connectors)和网络连接器(network connectors)。
- 可插拔的持久性和安全----ActiveMQ提供多种持久性方案可供选择,也可以完全按自己需求定制验证和授权。例如,ActiveMQ通过KahaDB提供自己的超快速消息持久方案(ultra-fast
message persistence),但也支持标准的JDBC方案。ActiveMQ可以通过配置文件提供简单的验证和授权,也提供标准的JAAS登陆模块。这两部分内容将在5,6章论述。
- 用Java建立消息驱动应用----ActiveMQ最常用在Java应用中,用于发送和接收消息。这部分的内容涉及JMS规范API,将会在第7章讨论。
- 与应用服务器集成----ActiveMQ与java应用服务器集成是很常见的。第8章提供了一些集成例子,包括Apache
Tomcat,Jetty,Apache Geronimo和JBoss。
- 客户端APIs----ActiveMQ对多种语言提供客户端API,除了Java之外还有C/C++,.NET,Perl,PHP,Python,Ruby等。这使得ActiveMQ能用在Java之外的其它语言中。很多其它语言都可以通过ActiveMQ提供的客户端API使用ActiveMQ的全部特性。当然,ActiveMQ代理器(broker)仍然是运行在java虚拟机上,但是客户端能够使用其它的被支持的语言。客户端和ActiveMQ的连接将在第9章讨论。
- 代理器集群(Broker clustering)----为了利于扩展,多个ActiveMQ broker能够联合工作。这个方式就是network
of brokers并且能支持多种拓扑结构。这部分将在第10章讨论。
- 高级代理器特性和客户端选项----ActiveMQ为代理器和客户端连接提供很多高级的特性。ActiveMQ也可以通过代理器的XML配置文件支持Apache
Camel。这部分内容将在11和12章介绍。
- 简单的管理----ActiveMQ是为开发者设计的。它并不需要专门的管理工具,因为它提供各种易用且强大的管理特性。有很多方法去监控ActiveMQ的各个方面,可以通过JMX使用JConsole或ActiveMQ
web console;可以运行ActiveMQ消息报告;可以用命令行脚本;可以通过日志。这些都会在第14章介绍。
上面只是简单介绍了ActiveMQ的特性。就像你看到的,这些特性将在全书的各个章节讨论。为了演示,第3章将带来一些简单例子。但在看这些例子和特性之前,你一定想知道为什么要使用ActiveMQ。
1.2使用ActiveMQ:为什么,何时
时间回到2003年,一群开源开发者集合在一起形成了Apache Geronimo。之后,他们发现当前没有好用的使用BSD-style许可协议的消息代理器。Geronimo是由于java
EE兼容性需要一个JMS实现。所以一些开发者开始讨论其可能性。拥有丰富MOMs经验甚至自己创建过一些MOMs的这些开发者开始创建下一个伟大的开源消息代理。ActiveMQ这么快开始是因为当时市场上大多数的MOMs是商业,闭源而且购买和支持昂贵。市场上的MOMs已经广泛地被使用,但是一些商业行为是买不起如此昂贵的软件。这使得创建一个开源MOMs的需求更加大。很明显,有一个市场急需一个开源的使用Apache
License的MOM。最终就导致了Apache ActiveMQ的诞生。
ActiveMQ遵循JMS规范,是为分布式应用远程交流而创建的。为了理解这目的,最好就是去看一些分布式应用的设计和是交互。
1.2.1松耦合与ActiveMQ
ActiveMQ提供松耦合的应用架构。松耦合一般是为了减轻经典RPC(Remote
Procedure Calls)调用的紧耦合架构而被引入的。该松耦合以异步形式存在,任何一个应用对ActiveMQ的调用不依赖于任何其它应用,没有任何依赖或者时序要求。应用依赖于ActiveMQ的能力保证消息传递。因此,我们把应用发送消息的形式称之为触发和忘记(fire-and-forget)--应用发送消息到ActiveMQ之后并不关心消息如何或者什么时候被传递。同样的消息的接收者也不关心消息从哪里或者如何到来。在不同的环境中这样做的好处是允许客户端使用不同的语言编写甚至使用不同的线路协议。ActiveMQ作为中间人存在,允许不同环境的集成和异步交互。更多内容将在下一节论述。
当我们考虑分布式应用设计时,耦合是很重要的。耦合是指两个或多个应用间的相互依赖。考虑耦合的一个简单办法是思考其中某个应用改变所产生的影响,即其它应用所需要作出的改变。是否一个应用的变化会强制其它应用跟着改变?如果答案是肯定的,则这些应用是紧耦合的。如果一个应用的变化无需强制其它应用跟着改变,则这些应用是松耦合的。这说明了紧耦合系统比松耦合系统更难维护。也就是说,松耦合系统更能适应未知的变化。
在第二章我们将讨论COM,CORBA,DCE和EJB等使用RPC的技术,它们是紧耦合的。使用RPC,当一个应用调用另一个应用,调用者将被阻塞知道被调用者返回结果。图1.1描述了这个过程。
调用方(Application one)将被阻塞直到被调用方(Application
two)返回控制权。很多系统使用RPC并且成功了。但是对于这样一个紧耦合系统确实有很多缺点:最显著的缺点是,即使很小的一个改变都要较高的维护代价;正确的时机也很重要,当请求从应用1发到应用2时,两个系统都必须正常工作,同样的,响应从应用2发送到应用1时,两个系统也必须正常工作。这样的时序要求有点麻烦,使得系统稳定性降低。现在我们把这个紧耦合系统和图1.2的系统进行比较。
在图1.2中,应用1发送消息到MOM只是一个单方行为。可能一段时间后,应用2从MOM接收消息,这也是一个单方行为。任何一方都不需要知道另一方的存在,它们之间也没有任何时序要求。所以在分布式系统设计时,松耦合系统比紧耦合系统有巨大的优势。如图所示,这就是ActiveMQ存在的地方。
考虑现在其中的一个应用必须搬到一个新的地方。这可能在新硬件引入或应用需要移动时发生。如果是一个紧耦合系统,这样的迁移会很困难,因为系统的其它部分都必须停止工作等待迁移完成。如果是松耦合系统,系统的各个部分能够自由迁移而不影响其它部分。考虑这样一个场景,应用A和B各有很多个实例,其中各个实例分布在不同的机器上。ActiveMQ安装在另外的机器上。在这种情况下,任何一个应用实例都可以自由移动而不影响其它应用。事实上,多个ActiveMQ实例也可以通过network
of brokers配置联合使用。这就允许ActiveMQ实例自由迁移而不影响应用A或应用B。采用这种价构,系统的任何一部分在任何时间都可以停机进行维护而不影响整个系统。更多的介绍将放在第10章。
总之,ActiveMQ提供一个令人难以置信的灵活性允许松耦合思想变成现实。对于某些情况不能使用异步方式实现,ActiveMQ也提供消息的请求/回复模式支持。那么什么时候使用ActiveMQ可以获得如上所述的好处呢?
1.2.2何时使用ActiveMQ
有很多情况ActiveMQ和异步消息能对一个系统的架构产生有意义的作用。下面列举一些场景。
- 不同语言应用集成----ActiveMQ使用java编写,并且提供一个java客户端API。但ActiveMQ也为C/C++,.NET,Perl,PHP,Python,Ruby等提供客户端。当你考虑在不同平台不同语言下的各个应用进行集成时,这将是一个巨大的优势。不同语言的客户端API使各种不同的语言能够通过ActiveMQ发送和接收消息。对于ActiveMQ提供的多语言兼容,还有一个好处是相对于RPC调用,它能帮助系统各应用间的解耦。
- RPC的替代者----应用广泛的使用RPC模式的同步调用。想一下,现在大量使用RPC调用的客户端服务器模式的应用,它们包括ATMs,大多数web应用,信用卡系统,销售点(point-of-sale)系统等。尽管它们大多数是成功的,但是转换到异步消息模式能够在保证正确响应的情况下带来一些好处。使用同步请求的系统在规模上有较大的限制,因为请求会被阻塞,从而导致整个系统变慢。如果使用异步消息替代,可以很容易增加额外的消息接收者,使得消息能被并发消耗,从而加快请求处理。当然,必须你系统应用间是解耦的。
- 应用间解耦----就是上面讨论过的,紧耦合系统能带来很多问题,特别是在应用是分布式的情况下。松耦合系统,也就是依赖性小的系统,可以更好地适应未知变化。不只是系统某部分的改变不会影响整个系统,而且部件间的交互也更简单。相比使用同步的系统(调用者必须等待被调用者返回信息),异步系统(调用方发送消息后就不管,即fire-and-forget)能够给我们带来事件驱动架构(event-driven
architecture EDA).
- 作为事件驱动架构的骨架----解耦,异步架构的系统允许通过代理器自己配置更多的客户端,内存等(即vertical
scalability)来扩大系统,而不是增加更多的代理器(即horizontal scalability)。考虑如亚马逊这样繁忙的电子商务系统。当用户购买物品,事实上系统需要很多步骤去处理,包括下单,创建发票,付款,执行订单,运输等。但是用户下单后,会立即返回“谢谢你下单”的界面。不只是没有延迟,而且用户还会受到一封邮件表明订单已经收到。在亚马逊下单的例子就是一个多步处理的例子。每一步都由单独的服务去处理。当用户下单是,有一个同步的体积表单动作,但整个处理流程并不通过浏览器同步处理。相反地,订单马上被接受和反馈。而剩下的步骤就通过异步处理。如果在处理过程中出错,用户会通过邮件收到通知。这样的异步处理能提供高负载和高可用性。
- 提高系统扩展性。很多使用事件驱动设计的系统是为了获得高可扩展性,例如电子商务,政府,制造业,线上游戏等。通过异步消息分开商业处理步骤给各个应用,能够带来很多可能性。考虑设计一个应用来完成一项特殊的任务。这就是面向服务的架构(service-oriented
architecture SOA)。每一个服务完成一个功能并且只有一个功能。应用就通过服务组合起来,服务间使用异步消息和最终一致性。这样的设计便可以引入一个复杂事件处理概念(complex
event processing CEP)。使用CEP,部件间的交互可以被记录追踪。在异步消息系统中,可以很容易在部件间增加一层处理。
现在你已经了解了在哪里使用ActiveMQ,是时候安装和使用它了。
开始使用ActiveMQ
开始使用ActiveMQ并不难。你只要启动代理器并确保它能接受连接和发送消息。ActiveMQ有一些自带的例子能够帮你完成这个任务,不过首先你必须安装Java和下载ActiveMQ。
在这部分,你将下载和安装Java SE,下载和安装ActiveMQ,检查ActiveMQ目录,然后第一次启动ActiveMQ。
1.3.1下载和安装Java SE
ActiveMQ 要求Sun Java SE 1.5或以上。在开始这部分前,必须先安装。如果你没有,请从下面的地址下载并安装(for
Linux,Solaris,Windows)。http://www.oracle.com/technetwork/java/javase/downloads/index.html.如果你是Mac
OS X系统,你应该已经装有Java SE。如果没有,请从下面网址下载。URL: http://developer.apple.com/java/download/。
一旦你安装完毕,你必须测试下是否安装正确。你可以打开一个终端或命令行输入下面的命令。
最终的输出可能因你操作系统的不同而有的区别。这个命令告诉我们两件事:J2SE已正确安装,版本是1.6。如果你没有看见类似的输出,在进入下一步之前你必须使它正确。
下载和安装Ant
Ant可以用来构建和运行ActiveMQ自带例子。Ant可以从Apache
Ant网址下载。URL: http://ant.apache.org/
bindownload.cgi.
点击链接地址并选择正确的压缩包。(tar包是Linux和Unix,zip是Windows)。请按照下列地址安装Ant。URL:
http://ant.apache.org/manual/install.html。确保你设置好$ANT_HOME环境变量,并将$ANT_HOME/bin放到$PATH环境变量里。安装完毕后你可以运行下面的命令查看Ant版本。
$ ant -version Apache Ant version 1.8.1 compiled on April 30 2010
|
你可能使用Ant的不同版本,不过这没关系。一旦Ant输出如上信息,你就可以确定Java
SE和Ant都安装正确。
1.3.2下载ActiveMQ
ActiveMQ可以从Apache ActiveMQ网站下,URL:
http://activemq.apache.org/download.html.
点击地址到5.4.1版本,你可以看到tar和zip格式包。(tar包是Linux和Unix,zip是Windows)。下载完后解压。当你做完这步时,你必须正确安装了Java
SE。然后你就可以看一下ActiveMQ目录。
1.3.3检查ActiveMQ目录
从命令行进入apache-activemq-5.4.1目录,输入如下命令。
目录内容直白地显示了出来:
- LICENSE----Apache Software Foundation(ASF)要求的一个文件.包含ActiveMQ使用的所有库的许可证.
- NOTICE----ASF要求的另一个文件.包含ActiveMQ使用的所有库的版权信息.
- README.txt 一个包含一些URL的文档,使新手可以使用ActiveMQ.
- WebConsole-README.txt----包含使用ActiveMQ web console使用说明.
- activemq-all-5.4.1.jar---一个jar包包含ActiveMQ所有东西。放在这里是方便你使用它。
- bin----包含二进制或可运行文件。ActiveMQ启动脚本就放在里面。
- conf--ActiveMQ所有的配置信息。
- data--日志和持久化文件存储地方。
- docs--包含一个简单的index.html,该文件指向ActiveMQ网站。
- example----ActiveMQ例子。我们用这些例子来简单的测试ActiveMQ。
- lib----所有ActiveMQ所需库。
- user-guide.html----一个简单指引启动ActiveMQ和运行例子。
- webapps----ActiveMQ web console和一些网络演示。
下一部分将启动ActiveMQ并用这些例子验证它。
1.3.4启动ActiveMQ
下载和解压后,ActiveMQ已经可以使用。二进制包提供一个基础的配置使你能够启动并运行我们将要用到的例子。所以请照下面运行ActiveMQ。
$ ./bin/activemq console
INFO: Using default configuration
(you can configure options in one of these file: /etc/default/activemq
/Users/bsnyder/.activemqrc)
INFO: Invoke the following command to create a configuration file
./bin/activemq setup [ /etc/default/activemq | /Users/bsnyder/.activemqrc ]
INFO: Using java '/System/Library/Frameworks/JavaVM.framework/Home/bin/java'
INFO: Starting in foreground, this is just for debugging purposes
(stop process by pressing CTRL+C)
Java Runtime: Apple Inc. 1.6.0_20
/System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Home
Heap sizes: current=258880k free=253105k max=258880k
JVM args: -Xms256M -Xmx256M
-Dorg.apache.activemq.UseDedicatedTaskRunner=true
-Djava.util.logging.config.file=logging.properties
-Dcom.sun.management.jmxremote
-Dactivemq.classpath=/Users/bsnyder/amq/apache-activemq-5.4.1/conf;
-Dactivemq.home=/Users/bsnyder/amq/apache-activemq-5.4.1
-Dactivemq.base=/Users/bsnyder/amq/apache-activemq-5.4.1
ACTIVEMQ_HOME: /Users/bsnyder/amq/apache-activemq-5.4.1
ACTIVEMQ_BASE: /Users/bsnyder/amq/apache-activemq-5.4.1
Loading message broker from: xbean:activemq.xml
WARN | destroyApplicationContextOnStop parameter is deprecated,
please use shutdown hooks instead
INFO | PListStore:/Users/bsnyder/amq/apache-activemq-5.4.1/data/localhost/
tmp_storage started INFO | Using Persistence Adapter:
KahaDBPersistenceAdapter[/Users/bsnyder/amq/apache-activemq-5.4.1/data/
kahadb]
INFO | KahaDB is version 2
INFO | Recovering from the journal ...
INFO | Recovery replayed 1 operations from the journal in 0.029 seconds.
INFO | ActiveMQ 5.4.1 JMS Message Broker (localhost) is starting
...
INFO | ActiveMQ Console at http://0.0.0.0:8161/admin
INFO | Initializing Spring root WebApplicationContext
INFO | Connector vm://localhost Started
INFO | Camel Console at http://0.0.0.0:8161/camel
INFO | ActiveMQ Web Demos at http://0.0.0.0:8161/demo
INFO | RESTful file access application at http://0.0.0.0:
INFO | Started SelectChannelConnector@0.0.0.0:8161 |
注意:这本书使用的例子是Mac OS X,一个Unix操作系统。对于Windows用户,不要用‘console’参数。应使用如下命令
C:\apache-activemq-5.4.1>bin\activemq
请注意在windows下启动activemq命令是不包含console的,这对本书的所有例子都一样。
刚才的命令启动了ActiveMQ代理器和一些连接器,使得客户端可以通过一些诸如TCP,SSL,STOMP,XMPP协议连接进来。请注意现在ActiveMQ已经启动,并且客户端可以通过TCP
61616端口连接进来。这些都是可以配置的,我们将在第4章讨论。现在,上面的输出说明了ActiveMQ已启动并可以使用。现在应用让它处理一些消息了。最好的方法是使用ActiveMQ自带的例子来发送和接收消息。下一部分将一步一步教你做。
1.4运行ActiveMQ第一个例子
前面部分已经教你启动ActiveMQ。作为确认,你应该打开一些终端来运行ActiveMQ示例。在第二个终端中,移动到example文件夹并查看它的内容。如清单1.4所示。
[apache-activemq-5.4.1]$ cd ./example/ bsnyder@mongoose [example]$ ls -1 build.xml conf perfharness ruby src transactions
|
example目录包含了一些不同的东西。下面是一个简单的说明。
- build.xml----使用Java例子时需要的Ant配置文件。
- conf----使用Java例子的配置文件。
- perfharness----包含一个可以运行IBM JMS性能监控工具的脚本。
- ruby----包含一些使用Ruby和STOMP连接ActiveMQ的例子。
- src----Java例子就在这里。这个文件夹被build.xml使用。
- tansactions----一个带事务的ActiveMQ实现例子,这个例子是从Sun JMS教程弄过来的。
如列表1.5所示,用第二个终端启动JMS消费者。
Listing 1.5 Start up the ActiveMQ consumer
example
[example]$ ant consumer Buildfile: build.xml init: compile: consumer: [echo] Running consumer against server at $url = tcp://localhost:61616 for subject $subject = TEST.FOO [java] Connecting to URL: tcp://localhost:61616 [java] Consuming queue: TEST.FOO [java] Using a non-durable subscription [java] Running 1 parallel threads [java] [Thread-2] We are about to wait until we consume: 2000 message(s) then we will shutdown
|
这个命令编译java例子并启动一个简单的JMS消费者。就像你看到的,消费者:
- 使用tcp协议连接代理器(tcp://localhost:61616)
- 监听一个叫TEST.FOO的队列
- 使用非持久订阅(nondurable subscription)
- 接收2000条消息后关闭
总之,JMS消耗者连接到ActiveMQ并等待信息。现在你可以发送消息到TEST.FOO队列。
在第三个终端移动到example目录,如下启动一个JMS生产者。它将会立即开始发送消息。
Listing 1.6 Start up the ActiveMQ producer
example
[example]$ ant producer Buildfile: build.xml init: compile: producer: [echo] Running producer against server at $url = tcp://localhost:61616 for subject $subject = TEST.FOO [java] Connecting to URL: tcp://localhost:61616 [java] Publishing a Message with size 1000 to queue: TEST.FOO [java] Using non-persistent messages [java] Sleeping between publish 0 ms [java] Running 1 parallel threads [java] [Thread-2] Sending message: 'Message: 0 sent at: Thu Oct 14 21:24:07 MDT 2010 ...' [java] [Thread-2] Sending message: 'Message: 1 sent at: Thu Oct 14 21:24:07 MDT 2010 ...' [java] [Thread-2] Sending message: 'Message: 2 sent at: Thu Oct 14 21:24:07 MDT 2010 ...'
|
由于阅读方便,上面的输出省略了一些。但从上面你也可以了解到
- 它使用tcp协议连接代理器(tcp://localhost:61616)
- 向队列TEST.FOO发送消息
- 使用非持久性消息
- 在发送消息的间隙不休眠。
一旦JMS生产者连接上ActiveMQ,它将发送2000条消息后结束。这刚好是消费者关闭前所要消耗的消息数。当生产者在生产消息时,切换到终端2查看消费者怎么消耗这些信息。下面是终端2输出到消息
[java] [Thread-2] Received: 'Message: 0 sent at: Thu Oct 14 21:23:56 MDT 2010 ...' (length 1000) [java] [Thread-2] Received: 'Message: 1 sent at: Thu Oct 14 21:23:56 MDT 2010 ...' (length 1000) [java] [Thread-2] Received: 'Message: 2 sent at: Thu Oct 14 21:23:56 MDT 2010 ...' (length 1000) ... [java] [Thread-2] Received: 'Message: 1999 sent at: Thu Oct 14 21:23:56 MDT 2010 ...' (length 1000)
|
当然,因为可读性原因消息没有全部显示出来。不过我们还是可以看到消费者消费了2000条消息并关闭。这时,生产者和消费者都应该关闭了,并且ActiveMQ是正常运行的。我们再看回终端2,好像ActiveMQ什么都没做。这是因为默认的日志配置并不输出一些不必要的东西。如果你想让ActiveMQ输出接收和发送消息的日志,你可以修改日志配置。具体内容将在14章介绍。
这一节你学到了什么呢?通过使用ActiveMQ自带的例子,可以证明代理器已经启动,并且可以处理消息。这看起来没什么,但却是重要的第一步。如果你能成功运行这个例子,就说明你的网络连接没有问题,也说明ActiveMQ是正常的。如果你不能成功运行这个例子,你必须先找出错误。如果你需要帮助,通过ActiveMQ的邮件列表寻求帮助是最好的一种方法。这些例子只是让你开始使用ActiveMQ,但它们也能用来测试很多场景。这本书剩下的内容,有一些其它常用场景的例子,将用来演示ActiveMQ和它的特性。这些例子将在第3章详细解释。
本章总结
ActiveMQ是多功能的,易于使用的消息中间件。你了解了ActiveMQ的特性,这些特性将在这本书中详细讲述。你也了解了ActiveMQ使用场景。本章介绍的场景都是真实世界的例子,并且已经在商业上使用的。JMS规范就是设计在这些场景中使用的。对于那些不熟悉或者根本不懂JMS的人,下一章将向你介绍企业消息服务,并提供一个JMS总览。如果你多这两个内容很熟悉,你可以跳过第三章。
|