一、点对点模型概览
当你只需要将消息发布送给唯一的一个消息消费者是,就应该使用点对点模型。虽然可能或有多个消费者在队列中侦听统一消息,但是,只有一个且仅有一个消费者线程会接受到该消息。
在p2p模型中,生产者称为发送者,而消费者则称为接受者。点对点模型最重要的特性如下:
- 消息通过称为队列的一个虚拟通道来进行交换。队列是生产者发送消息的目的地和接受者消费消息的消息源。
- 每条消息通仅会传送给一个接受者。可能会有多个接受者在一个队列中侦听,但是每个队列中的消息只能被队列中的一个接受者消费。
- 消息存在先后顺序。一个队列会按照消息服务器将消息放入队列中的顺序,把它们传送给消费者当消息已被消费时,就会从队列头部将它们删除。
- 生产者和消费者之间没有耦合。接受者和发送者可以在运行时动态添加,这使得系统的复杂性可以随着时间而增长或降低(这是消息传送系统的普遍特性)。
点对点消息传送模型有两种类型:异步即发即弃(fire-and-forget)处理和异步请求/应答处理。使用即发即弃处理时,消息生产者向某个队列发送一条消息,而且它并不会期望接受到一个响应(至少不是立刻接收到响应)。这类处理可用于触发一个事件,或者用于向接受者发出请求来执行一个并不需要响应的特定活动。异步即发即弃处理如图4-1所示:
>
使用异步请求/应答处理时,消息生产者向队里发送一条消息,然后阻塞等待(blocking wait)应答队列,该应答队列正在等待来自接受者的响应。请求/应答处理实现了生产者和消费者之间的高度去耦,允许消息生产者和消费者组件采用不同的语言或平台。异步请求/应答处理如下图所示:
用于连接、创建、发送和接受的特定p2p接口见表:
公共API 点对点模型API ConnectionFactory QueueConnectionFactory Destination Queue Connection QueueConnection Session QueueSession MessageConsumer QueueSender MessageProducer QueueReceiver
1.1 何时使用点对点消息传送模型
JMS的初衷是要提供一种公共API的方法,用于访问现有的消息传送系统。在提出JMS规范概念的时候,一些消息传送系统厂商使用的是P2P模型,而另一些厂商使用的则是发布/订阅模型。
当你想让接受者对某个指定的消息进行一次而且仅仅一次处理时,就必须使用点对点模型。这可能是这两种模型之间的最重要的区别:点对点模型只会保证只有一个消费者来处理一条指定的消息。在消息要移除分别接受处理时,要在多个JMS客户端之间均衡消息处理的负载,这是极为重要的。点对点模型的另一优点就是,它所提供的QueueBrowser允许JMS客户端对队列进行快照(Snapshot),以查看正在等待被消费的消息。发布/订阅模型则没有这种浏览特性。
点对点消息传送模型的另一个用例是:您需要在组件之间进行同步通信,而那些组件却是用不同的编程语言编写的,或者是在不同的技术平台(如J2EE或.NET)上实现的。
使用点对点消息传送模型的另一个充分理由是:使用基于消息的负载均衡,可以让服务端的组件实现更大的吞吐量,特别是对于同构组件来说更是如此。
1.2 QBorrower和Qlender应用程序
为了说明点对点消息传送模型是如何工作的,我们将使用一个简单去耦的请求/应答用例。其中,QBorrower类使用点对点消息传送,向QLender类发出了一个简单的抵押贷款申请。QBorrower类使用LoanRequest队列,向QLender类发送贷款申请,而且根据特定的业务规则,QLender类使用LoanResponseQ队列向QBorrower类发回一个响应,表明该LoanRequest是被批准还是拒绝。由于QBorrower感兴趣的是要马上弄清楚贷款批准与否,一旦LoanRequest被发送出去,QBorrower类就会阻塞,并一直等待来自QLender类的响应,无响应就不再继续进行工作。
1.2.1 配置并运行应用程序
- 安装下载ActiveMQ并运行,如下图所示
- 配置发送接收队列:进入activeMQ的conf目录中,打开activemq.xml文件,在其中增加如下代码:
<destinations>
<queue name="LoanRequestQ" physicalName="jms.LoanRequestQ"/>
<queue name="LoanResponseQ" physicalName="jms.LoanResponseQ"/>
</destinations>
重新启动MQ,启动成功后打开浏览器输入网址:http://127.0.0.1:8161/,选择Queues可看到我们刚才加进来的队列,如下图
3.在程序中生成一个配置文件jndi.properties,内容如下:
4.我们再来看一张我们的程序运行示意图:
1.2.2 QBorrower类
QBorrowerl 类负责向包含工资额和贷款额的一个队列发送LoanRequest消息。这个类非常简单:构造函数建立一个到JMS提供者的连接,创建一个QueueSession,并使用JNDI查找获得请求和响应队列。
package cn.com.paner.jms.p2p;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.nio.Buffer;
import java.util.StringTokenizer;
import java.util.UUID;
import javax.jms.JMSException;
import javax.jms.MapMessage;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueReceiver;
import javax.jms.QueueSender;
import javax.jm