当前位置: 首页 > ActiveMQ in Action 读书笔记 > 正文

7.3 使用 JMS 实现请求/应答程序

7.3 Implementing request/reply with JMS

As described in earlier chapters, messaging is all about the decoupling of senders fromreceivers. Messages are sent by one process to a broker, and messages are received froma broker by a different process in an asynchronous manner. One style of system architecturethat can be implemented using JMS is known as request/reply. From a high level,a request/reply scenario involves an application that sends a message (the request)and expects to receive a message in return (the reply). Traditionally, such a systemdesign was implemented using a client-server architecture, with the server and the clientcommunicating in a synchronous manner across a network transport (TCP, UDP,and so on). This style of architecture certainly has scalability limitations, and it’s difficultto distribute it further. That’s where messaging enters the picture—to provide theability to design a system that can easily scale much further via a messaging-basedrequest/reply design. Some of the most scalable systems in the world are implementedusing asynchronous processing like that being demonstrated in this example.

7.3 使用 JMS 实现请求/应答程序


The diagram shown in figure 7.2 depicts an overview of the request/reply paradigm.Note that the client consists of both a producer and a consumer, and theworker also consists of both a producer and a consumer. These two entities are bothexplained next.

图7.2 是请求/应答系统的示例.注意,客户端包含消息生产者(producer)和消息消费者(consumer),并且工作者(worker)也包含消息生产者(producer)和消息消费者(consumer).后面将解释客户端和工作者(worker).

First, the producer creates a request in the form of a JMS message and sets a coupleof important properties on the message—the correlation ID (set via the message property) and the reply destination (set via the JMSReplyTomessage property). The correlation ID is important, as it allows requests to be correlatedwith replies if there are multiple outstanding requests. The reply destination iswhere the reply is expected to be delivered (usually a temporary JMS destination sinceit’s much more resource friendly). The client then configures a consumer to listen onthe reply destination.

首先,消息生产者创建一个以JMS消息格式封装的请求并在消息中设置一些重要的属性,包括correlation ID(通过消息的JMSCorrelationID属性设置)和reply destination(响应发送目的地,通过JMSReplyTo属性设置).correlation ID属性非常重要,因为在请求数量非常多时需要使用这个属性来关联请求和应答.reply destination属性指定应答发往的目的地(通常是一个临时的JMS目的地,因为reply destination比较消耗资源).接下来,客户端配置一个消息消费者监听响应消息目的地(reply destination).

Second, a worker receives the request, processes it, and sends a reply messageusing the destination named in the JMSReplyTo property of the request message. Thereply message must also set JMSCorrelationID using the correlation ID from the original request.When the client receives this reply message, it can then properly associateit with the original request.

其次,一个工作者(woker)接收到请求,并处理请求,然后发送一个响应消息到请求消息的JMSReplyTo属性指定的目的中.响应消息必须用原始请求消息correlation ID的属性值来设置JMSCorrelationID属性,当客户端收到响应消息后,可以通过correlation ID关联到初始的请求.

Now comes the interesting part—to demonstrate how this architecture can behighly scalable. Imagine that a single worker isn’t enough to handle the load ofincoming requests. No problem: just add additional workers to handle the load.


Those workers can even be distributed across multiple hosts—this is the most importantaspect of scaling this design. Because the workers aren’t contending for the sameresources on the same host, the only limit is the maximum throughput of messagesthrough the broker, which is much higher than you can achieve with any classic clientserversetup. Furthermore, ActiveMQ can be scaled both vertically and horizontally, asdiscussed in part 4. Let’s now take a look at a simple implementation of request/reply.


7.3.1 Implementing the server and the worker

The first piece of the system on which to focus is the message broker. Get the brokerup and running so that it’s ready for connections when both sides are started up. Anembedded broker will be used for this example because it’s easy to demonstrate. Thesecond piece of the system to get running is the worker. The worker is composed of amessage listener that consumes the message and sends a response. Even though this isa simple implementation, it’ll provide you enough information to use it with your systems.So take a look at the server implementation.
Listing 7.14 Create a broker, a consumer, and a producer for the request/reply example

7.3.1 实现服务和工作者(worker)


代码清单7.14 在请求/响应实例创建中一个代理,消费者以及生产者

As you can see, the start() method calls one method to create and start an embeddedbroker, and another method to create and start up the worker. The createBroker() method uses the BrokerService class to create an embedded broker. ThesetupConsumer() method creates all the necessary JMS objects for receiving and sending messages including a connection, a session, a destination, a consumer, and a producer.


The producer is created without a default destination, because it’ll sendmessages to destinations that are specified in each message’s JMSReplyTo property.Taking a closer look at the listener, note how it handles the consumption of eachrequest as shown next.
Listing 7.15 The message listener for the request/reply example


代码清单7.15 请求/响应实例中的消息监听者

The listener creates a new message, assigns the appropriate correlation ID, and sendsa message to the reply-to queue. Simple stuff, but still important. Although this messagelistener isn’t earth shattering in its implementation, it demonstrates the basicsteps necessary to complete the task of the worker. Any amount of extra processing ordatabase access could be added to the listener in your systems depending on therequirements.

消息监听器创建一个新消息,并设置合适的correlation ID,然后将消息发送到响应消息队列.很简单但是很重要.尽管在这个消息监听器的实现中没做什么惊天动地的事情,但是它展示了工作者完成器任务的必要的基本步骤.根据需求,,可以在监听器中添加其他任意额外的操作或者数据库访问操作.

Starting the server is rather obvious: create an instance of it and call the start()method. All of the server functionality is housed in the main method, as shown in thefollowing listing.

Listing 7.16 Starting the server for the request-reply example


代码清单 7.16 启动request-reply实例的服务器


Once the server is started and the worker is running, everything is ready to accept
requests from the client.


7.3.2 Implementing the client

The job of the client is to initiate requests to the broker. This is where the wholerequest/reply process begins, and is typically triggered by one of your business processes.This process could be to accept an order, fulfill an order, integrate various businesssystems, or buy or sell a financial position. Whatever the case may be, request/replybegins by sending a message.

7.3.2 实现客户端


Sending a message to the broker requires the standard connection, session, destination,and producer which are all created in the client by the start() method. Thisis all shown in the following listing.

Listing 7.17 Methods for starting and stopping the request/reply client


代码清单7.17 启动和停止响应/应答系统客户端的方法

The producer sends a message to the request queue and then the consumer listens onthe newly created temporary queue. Now it’s time to implement an actual logic for theclient, as shown next.

Listing 7.18 Implementation of logic for request/reply client


代码清单7.18 实现客户端请求/应答逻辑

The request() method shown in listing 7.18 creates a message with the request content,sets the JMSReplyTo property to the temporary queue, and sets the correlationID—these three items are important. Although the correlation ID in this case uses arandom UUID, just about any ID generator can be used. Now we’re ready to send arequest.

代码清单7.18中所示的request()方法使用请求内容创建一个消息并设置JMSReplyTo属性值,接着发送这个消息到临时队列,最后设置correlation ID 属性值.上述3个步骤很重要.在这个例子中,是使用一个随机的UUID值来设置correlation ID的,也还可以使用其他任何ID生成器来生成这个ID.接下就可以发送一个请求了.

Just like starting the server was a simple main method, the same is true of the clientas shown in the next listing.
Listing 7.19 Starting the request/reply client

代码清单7.19 启动请求/应答系统客户端

As explained earlier, this is a simple implementation. So upon starting up the client,10 requests are sent to the broker. Now it’s time to actually run the example.


7.3.3 Running the request/reply example

Running the example requires two terminals: one for the server and one for the client.The server needs to be started first. The server is implemented in a class namedServer and the client is implemented in a class named Client. Because each of theseclasses is initiated via a main method, it’s easy to start each one. The following listingdemonstrates starting up the server class.
Listing 7.20 Start up the server for the request/reply example

7.3.3 运行请求/应答实例程序

代码清单 7.20 启动request/reply实例的服务器

When the server is started up, then it’s time to start up the client and begin sendingrequests. The following listing shows how to start up the client.
Listing 7.21 Start up the client for the request/reply example

代码清单7.21 启动请求/响应实例客户端(client)

 $ mvn exec:java -Dexec.mainClass=org.apache.activemq.book.ch7.sync.Client

Note that when the client is started, 10 requests are sent to initiate the request/replyprocess and 10 replies are received back from the worker. Although it’s not glorious,the power in this simple request/reply example will become evident when you apply itto your own business processes.

Using the request/reply pattern, envision that there are thousands of requestsentering the broker every second from many clients, all distributed across many hosts.



In a production system, more than just a single broker instance would be used for thepurposes of redundancy, failover, and load balancing. These brokers would also bedistributed across many hosts. The only way to handle this many requests would be touse many workers. Producers can always send messages much faster than a consumercan receive and process them, so lots of workers would be needed, all of them spreadout across many hosts as well.


The advantage of using many workers is that each onecan go up and down at will, and the overall system itself isn’t affected. The producersand workers would continue to process messages, and even if one of them crashed, itwouldn’t affect the system. This is exactly how many large-scale systems can handlesuch a tremendous load—through the use of asynchronous messaging like that demonstratedby the request/reply pattern.


The JMS API can be tedious, as it requires you to write a lot of code for initializingall the necessary JMS objects such as connections, sessions, producers, consumers, andso forth. This is where the Spring Framework provides a lot of benefit. It helps you toremove such boilerplate code by supplying a more cogent API and by simplifying theoverall configuration.

JMS的API可以说是繁琐的,因为它要求开发者书写大量的初始化代码用于初始化必要的JMS对象,包括connection, session, producer, consumer等等.使用Spring框架通过提供可靠的API来帮助开发者移除(类似于JMS对象初始化)的哪些固定的代码,以便简化整个配置过程.这正式使用Spring框架带来的好处.


   微信打赏  支付宝打赏

本文固定链接: https://www.jack-yin.com/coding/translation/activemq-in-action/1558.html | 边城网事

该日志由 边城网事 于2013年11月11日发表在 ActiveMQ in Action 读书笔记 分类下, 你可以发表评论,并在保留原文地址及作者的情况下引用到你的网站或博客。
原创文章转载请注明: 7.3 使用 JMS 实现请求/应答程序 | 边城网事
关键字: , ,

7.3 使用 JMS 实现请求/应答程序:目前有2 条留言

  1. 沙发


    2015-04-22 11:37 [回复]