当前,CORBA、DCOM、RMI等RPC中间件技术已广泛应用于各个领域。但是面对规模和复杂度都越来越高的分布式系统,这些技术也显示出其局限性:(1)同步通信:客户发出调用后,必须等待服务对象完成处理并返回结果后才能继续执行;(2)客户和服务对象的生命周期紧密耦合:客户进程和服务对象进程都必须正常运行;如果由于服务对象崩溃或者网络故障导致客户的请求不可达,客户会接收到异常;(3)点对点通信:客户的一次调用只发送给某个单独的目标对象。
面向消息的中间件(Message Oriented Middleware,MOM)较好的解决了以上问题。发送者将消息发送给消息服务器,消息服务器将消息存放在若干队列中,在合适的时候再将消息转发给接收者。这种模式下,发送和接收是异步的,发送者无需等待;二者的生命周期未必相同:发送消息的时候接收者不一定运行,接收消息的时候发送者也不一定运行;一对多通信:对于一个消息可以有多个接收者。
已有的MOM系统包括IBM的MQSeries、Microsoft的MSMQ和BEA的MessageQ等。由于没有一个通用的标准,这些系统很难实现互操作和无缝连接。Java Message Service(JMS)是SUN提出的旨在统一各种MOM系统接口的规范,它包含点对点(Point to Point,PTP)和发布/订阅(Publish/Subscribe,pub/sub)两种消息模型,提供可靠消息传输、事务和消息过滤等机制。
1.JMS
JAVA 消息服务(JMS)定义了Java 中访问消息中间件的接口。JMS 只是接口,并没有给予实现,实现JMS 接口的消息中间件称为JMS Provider,iLink实现了JMS接口,用户可以通过使用JMS接口,在iLink中进行JMS编程。 iLink支持JMS1.0.2版本。
2.JMS接口描述
JMS 支持两种消息类型PTP 和Pub/Sub,分别称作:PTP Domain 和Pub/Sub Domain,这两种接口都继承统一的JMS父接口,JMS 主要接口如下所示:
ConnectionFactory :连接工厂,JMS 用它创建连接
Connection :JMS 客户端到JMS Provider 的连接
Destination :消息的目的地
Session: 一个发送或接收消息的线程
MessageProducer: 由Session 对象创建的用来发送消息的对象
MessageConsumer: 由Session 对象创建的用来接收消息的对象
3.JMS消息模型
JMS 消息由以下几部分组成:消息头,属性,消息体。
3.1 消息头(Header) - 消息头包含消息的识别信息和路由信息,消息头包含一些标准的属性如:JMSDestination,JMSMessageID 等。
3.2 属性(Properties) - 除了消息头中定义好的标准属性外,JMS 提供一种机制增加新属性到消息头 中,这种新属性包含以下几种:
1. 应用需要用到的属性;
2. 消息头中原有的一些可选属性;
3. JMS Provider 需要用到的属性。
标准的JMS 消息头包含以下属性:
3.3 消息体(Body) - JMS API 定义了5种消息体格式,也叫消息类型,你可以使用不同形式发送接收 数据并可以兼容现有的消息格式,下面描述这5种类型:
消息类型 | 消息体 |
TextMessage | java.lang.String对象,如xml文件内容 |
MapMessage | 名/值对的集合,名是String对象,值类型可以是Java任何基本类型 |
BytesMessage | 字节流 |
StreamMessage | Java中的输入输出流 |
ObjectMessage | Java中的可序列化对象 |
Message | 没有消息体,只有消息头和属性 |
下例演示创建并发送一个TextMessage到一个队列:
TextMessage message = queueSession.createTextMessage();
message.setText(msg_text); // msg_text is a String
queueSender.send(message);
下例演示接收消息并转换为合适的消息类型:
Message m = queueReceiver.receive();
if (m instanceof TextMessage) {
TextMessage message = (TextMessage) m;
System.out.println("Reading message: " + message.getText());
} else {
// Handle error
}
4.消息的同步异步接收
消息的同步接收是指客户端主动去接收消息,JMS 客户端可以采用MessageConsumer 的receive方法去接收下一个消息。
消息的异步接收是指当消息到达时,主动通知客户端。JMS 客户端可以通过注册一个实 现MessageListener 接口的对象到MessageConsumer,这样,每当消息到达时,JMS Provider 会调用MessageListener中的onMessage 方法。
5. PTP模型
PTP(Point-to-Point)模型是基于队列的,发送方发消息到队列,接收方从队列接收消息,队列的存在使得消息的异步传输成为可能。和邮件系统中的邮箱一样,队列可以包含各种消息,JMS Provider 提 供工具管理队列的创建、删除。JMS PTP 模型定义了客户端如何向队列发送消息,从队列接收消息,浏览队列中的消息。
下面描述JMS PTP 模型中的主要概念和对象:
名称 | 描述 |
Queue | 由JMS Provider 管理,队列由队列名识别,客户端可以通过JNDI 接口用队列名得到一个队列对象。 |
TemporaryQueue | 由QueueConnection 创建,而且只能由创建它的QueueConnection 使用。 |
QueueConnectionFactory | 客户端用QueueConnectionFactory 创建QueueConnection 对象。 |
QueueConnection | 一个到JMS PTP provider 的连接,客户端可以用QueueConnection 创建QueueSession 来发送和接收消息。 |
QueueSession | 提供一些方法创建QueueReceiver 、QueueSender、QueueBrowser 和TemporaryQueue。如果在QueueSession 关闭时,有一些消息已经被收到,但还没有被签收(acknowledged),那么,当接收者下次连接到相同的队列时,这些消息还会被再次接收。 |
QueueReceiver | 客户端用QueueReceiver 接收队列中的消息,如果用户在QueueReceiver 中设定了消息选择条件,那么不符合条件的消息会留在队列中,不会被接收到。 |
QueueSender | 客户端用QueueSender 发送消息到队列。 |
QueueBrowser | 客户端可以QueueBrowser 浏览队列中的消息,但不会收走消息。 |
QueueRequestor | JMS 提供QueueRequestor 类简化消息的收发过程。QueueRequestor 的构造函数有两个参数:QueueSession 和queue,QueueRequestor 通过创建一个临时队列来完成最终的收发消息请求。 |
可靠性(Reliability) | 队列可以长久地保存消息直到接收者收到消息。接收者不需要因为担心消息会丢失而时刻和队列保持激活的连接状态,充分体现了异步传输模式的优势。 |
JMS Pub/Sub 模型定义了如何向一个内容节点发布和订阅消息,这些节点被称作主题(topic)。
主题可以被认为是消息的传输中介,发布者(publisher)发布消息到主题,订阅者(subscribe)从主题订阅消息。主题使得消息订阅者和消息发布者保持互相独立,不需要接触即可保证消息的传送。
下面描述JMS Pub/Sub 模型中的主要概念和对象:
|
7. 开发JMS的步骤
广义上说,一个JMS 应用是几个JMS 客户端交换消息,开发JMS 客户端应用由以下几步构成:
用JNDI 得到ConnectionFactory 对象;
用JNDI 得到目标队列或主题对象,即Destination 对象;
用ConnectionFactory 创建Connection 对象;
用Connection 对象创建一个或多个JMS Session;
用Session 和Destination 创建MessageProducer 和MessageConsumer;
通知Connection 开始传递消息。