Java 消息服务(Java Message Service,JMS)
应用程序接口是一个Java 平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或
分布式系统中发送消息,进行
异步通信。Java 消息服务是一个与具体平台无关的 API,绝大多数 MOM 提供商都对 JMS 提供支持。
消息服务简介
Java 消息服务(Java Message Service,JMS)是一种与厂商无关的 API,用来访问消息收发系统。它类似于 JDBC (Java Database Connectivity):这里,JDBC 是可以用来访问许多不同关系数据库的 API,而 JMS 则提供同样与厂商无关的访问方法,以访问消息收发服务。许多厂目前都支持 JMS,包括
IBM 的 MQSeries、
BEA的 Weblogic JMS service和 Progress 的 SonicMQ,这只是几个例子。 JMS 使您能够通过消息收发服务(有时称为消息中介程序或路由器)从一个 JMS 客户机向另一个 JML 客户机发送消息。消息是 JMS 中的一种类型对象,由两部分组成:报头和消息主体。报头由路由信息以及有关该消息的
元数据组成。消息主体则携带着应用程序的数据或
有效负载。根据有效负载的类型来划分,可以将消息分为几种类型,它们分别携带:简单文本 (TextMessage)、可
序列化的对象 (ObjectMessage)、属性集合 (MapMessage)、
字节流 (BytesMessage)、原始值流 (StreamMessage),还有无有效负载的消息 (Message)。
通信传递的消息交换了计算机之间至关重要的数据——而非用户之间——并且包含了例如事件通知和服务请求之类的信息。通信通常用来协调在不同的系统中或是用不同的编程语言所写的程序。
使用JMS接口,程序员可以调用IBM的MQSeries,Progress Software的SonicMQ和其他流行通信产品商家的消息服务。另外,JMS支持包含串行Java对象的消息和包含可扩展标记语言(XML)页面的消息。
模式
Java 消息服务的规范包括两种消息模式,
点对点和发布者/订阅者。许多提供商支持这一通用框架因此,
程序员可以在他们的分布式软件中实现面向消息的操作,这些操作将具有不同面向
消息中间件产品的可移植性。
Java 消息服务支持同步和
异步的消息处理,在某些场景下,异步消息是必要的;在其他场景下,异步消息比同步消息操作更加便利。
Java 消息服务支持面向事件的方法接收消息,事件驱动的程序设计现在被广泛认为是一种富有成效的程序设计范例,程序员们都相当熟悉。
在应用系统开发时,Java 消息服务可以推迟选择面对
消息中间件产品,也可以在不同的面对消息中间件切换。
异步消息收发
消息收发系统是
异步的,也就是说,JMS 客户端可以发送消息而不必等待回应。比较可知,这完全不同于基于 RPC 的(基于远程过程的)系统,如 EJB 1.1、CORBA 和 Java RMI 的引用实现。在 RPC 中,客户机调用服务器上某个分布式对象的一个方法。在方法调用返回之前,该客户机被阻塞;该客户机在可以执行下一条指令之前,必须等待方法调用结束。在 JMS 中,客户机将消息发送给一个虚拟通道(主题或队列),而其它 JMS 客户机则预订或监听这个虚拟通道。当 JMS 客户机发送消息时,它并不等待回应。它执行发送操作,然后继续执行下一条指令。消息可能最终转发到一个或许多个客户机,这些客户机都不需要作出回应。
JMS 的通用接口集合以异步方式发送或接收消息。异步方式接收消息显然是使用间断网络连接的客户机,诸如移动电话和PDA的最好的选择。另外, JMS 采用一种宽松结合方式整合企业系统的方法,其主要的目的就是创建能够使用跨平台数据信息的、可移植的企业级应用程序,而把开发人力解放出来。
传递消息方式
JMS 有两种传递消息的方式。标记为 NON_PERSISTENT 的消息最多投递一次,而标记为 PERSISTENT 的消息将使用暂存后再转送的机理投递。如果一个 JMS 服务离线,那么持久性消息不会丢失,但是得等到这个服务恢复联机时才会被传递。所以默认的消息传递方式是非持久性的。即使使用非持久性消息可能降低内务和需要的
存储器,并且这种传递方式只有当你不需要接收所有的消息时才使用。
虽然 JMS 规范并不需要 JMS 供应商实现消息的优先级路线,但是它需要递送加快的消息优先于普通级别的消息。JMS 定义了从 0 到 9 的优先级路线级别,0 是最低的优先级而 9 则是最高的。更特殊的是 0 到 4 是正常优先级的变化幅度,而 5 到 9 是加快的优先级的变化幅度。举例来说: topicPublisher.publish (message, DeliveryMode.PERSISTENT, 8, 10000); //Pub-Sub 或 queueSender.send(message, DeliveryMode.PERSISTENT, 8, 10000);//P2P 这个代码片断,有两种消息模型,映射递送方式是持久的,优先级为加快型,生存周期是10000 (以
毫秒度量 )。如果生存周期设置为零,这则消息将永远不会过期。当消息需要时间限制否则将使其无效时,设置生存周期是有用的。
消息正文格式
JMS 定义了五种不同的消息正文格式,以及调用的消息类型,允许你发送并接收以一些不同形式的数据,提供现有消息格式的一些级别的兼容性。
· StreamMessage -- Java原始值的数据流
· MapMessage--一套名称-值对
· TextMessage--一个字符串对象
· ObjectMessage--一个
序列化的 Java对象
· BytesMessage--一个未解释字节的数据流
JMS
应用程序接口提供用于创建每种类型消息和设置荷载的方法例如,为了在一个队列创建并发送一个TextMessage实例,你可以使用下列语句: TextMessage message = queueSession.createTextMessage(); message.setText(textMsg); 以异步方式接收消息,需要创建一个消息
监听器然后注册一个或多个使用MessageConsumer的JMS MessageListener接口。会话(主题或队列)负责产生某些消息,这些消息被传送到使用onMessage方法的监听者那里。 import javax.jms.*; public class ExampleListener implements MessageListener { //把消息强制转化为TextMessage格式 public void onMessage(Message message) { TextMessage textMsg = null; // 打开并处理这段消息 } } 当我们创建QueueReceiver和TopicSubscriber时,我们传递消息选择器字符串: //P2P QueueReceiver QueueReceiver receiver; receiver = session.createReceiver(
queue, selector); //Pub-Sub TopicSubscriber TopicSubscriber subscriber; subscriber = session.createSubscriber(topic, selector);
为了启动消息的交付,不论是Pub/Sub还是P2P,都需要调用start方法。
当一条消息被捕捉时,这条消息做为一条必须被强制转化为适当消息类型的普通Message对象到达。这是一个被用来提取或打开消息内容的getter方法。下列代码片段使用StreamMessage类型。 private void unPackMessage (Message message) { String eName; String position; double rate; StreamMessage message; Message = session.createStreamMessage( ); //注意下面的代码必须按照我给出的顺序书写 message.writeString(eName); message.writeString(position); message.writeDouble(rate); //实现处理消息的必要的程序逻辑 }
停止消息的传递,无论是Pub/Sub还是P2P,都调用stop方法。 TopicConnection.start( ); //pub-sub QueueConnection.start( ); //P2P TopicConnection.start ( );// pub-sub QueueConnection.start ( );// P2P 其他的
J2EE组件--
servlet或
EJB--可以当作消息生产者;然而,它们可能只能同步操作,这可能是因为它们的请求-应答的性质决定的。虽然XML目前还不是被支持的消息类型,发送一个XML文件和创建一条文本类型消息以及把XML文件添加到消息的有效负载都一样简单,都是以非专有的方式传送数据。值得注意的是,一些JMS供应厂商已经提供了可用的XML消息类型。但是使用非标准的消息类型可能会出现可移植性问题。 String reportData; //reportData内容为XML 文档 TextMessage message; message = session.createTextMessage(); message.setText (reportData);
消息驱动组件
MDB 是一个当消息到达时被容器调用的异步消息消费程序。与 entity 和 session EJB 不同,MDB 没有本地和远程接口并且是匿名的;它们对于客户是不可见的。MDB 是 JMS 系统的一部分,作为消费者实现服务器上的
商业逻辑程序。 一个客户程序可能通过使用 JNDI 定位一个与 MDB 相关联的 JMS。 例如: Context initialContext = new InitialContext(); Queue reportInfoQueue = (javax.jms.Queue)initialContext.lookup (“java:comp/env/jms/reportInfoQueue”);
MDB是由Bean类和相应的XML部署描述符组成。 Bean 类实现MessageDriveBean 接口: import javax.ejb.*; import jms.Message.*; public interface MessageDriveBean { public void ejbCreate(); public void ejbRemove(); public void setMessageDrivenContext(MessageDrivenContext ctx); } 消息
监听器接口: import javax.jms.*; public interface MessageListener { public void onMessage( ); }
使用举例
既然我现在已经有了一些基本的 JMS知识,那么我们可以使用 JMS 做什么呢?任何事情都可以。例如,分别用于销售、库存、客户服务和账目处理的系统。这些部门之间的系统很可能已经存在了很长时间,这些处理要求把事务移动到系统中去,这并不是一个小的工作。这就是消息服务适用的地点。
当售货员完成销售的时候,一条消息被发给库存系统;一旦订单消息发送给收发货人员,就可以按照订单出货了。当订单成功地发货,系统将通知
顾客服务和
会计系统这个订单已经成功的交易了。所有对应的每个子系统都自动地根据收到的消息进行更新。
JMS 一般都不是用来整合一个系统,而是整合许多可能参与消息驱动环境的系统。JMS 是一个用于开发和集成企业应用程序的重要的工具。因为许多公司都有以前遗留下来的系统和新近开发的系统综合起来的情况,消息的使用是整合整个企业的重要步骤。