??xml version="1.0" encoding="utf-8" standalone="yes"?> JMS是一U与厂商无关?APIQ用来访问消息收发系l。它c?/u>g JDBC (Java Database Connectivity)Q这里,JDBC 是可以用来访问许多不同关p?/font>数据?/u>?APIQ?JMS 则提供同样与厂商无关的访问方法,以访问消息收发服务。许多厂商目前都支持 JMSQ包?IBM ?MQSeries、BEA?Weblogic JMS service?Progress ?SonicMQQ这只是几个例子? 消息收发pȝ是异步的Q也是_JMS 客户机可以发送消息而不必等待回应。比较可知,q完全不同于Z RPC 的(Zq程q程的)pȝQ如 EJB 1.1?a target=_new>CORBA ?Java RMI 的引用实现。在 RPC 中,客户用服务器上某个分布式对象的一个方法。在Ҏ调用q回之前Q该客户dQ该客户机在可以执行下一条指令之前,必须{待Ҏ调用l束。在 JMS 中,客户机将消息发送给一个虚拟通道Q主题或队列Q,而其?JMS 客户机则预订或监听这个虚拟通道。当 JMS 客户机发送消息时Q它q不{待回应。它执行发送操作,然后l箋执行下一条指令。消息可能最l{发到一个或许多个客hQ这些客h都不需要作出回应? JMS的通用接口集合以异步方式发送或接收消息。异步方式接收消息显然是使用间断|络q接的客hQ诸如移动电话和PDA的最好的选择。另外, JMS采用一U宽杄合方式整合企业系l的ҎQ其主要的目的就是创够用跨q_数据信息的、可UL的企业应用E序Q而把开发h力解攑և来?/font> Java消息服务支持两种消息模型QPoint-to-Point消息(P2P)和发布订阅消息(Publish Subscribe messagingQ简UPub/SubQ。JMS规范q不要求供应商同时支持这两种消息模型Q但开发者应该熟悉这两种消息模型的优势与~点?/font> P2P消息模型是在点对点之间传递消息时使用。如果应用程序开发者希望每一条消息都能够被处理,那么应该使用P2P消息模型。与Pub/Sub消息模型不同QP2P消息L能够被传送到指定的位|?/font> Pub/Sub模型在一到多的消息广播时使用。如果一定程度的消息传递的不可靠性可以被接受的话Q那么应用程序开发者也可以使用Pub/Sub消息模型。换句话_它适用于所有的消息消费E序q不要求能够收到所有的信息或者消息消费程序ƈ不想接收CQ何消息的情况?/font> JMS通过允许创徏持久订阅来简化时间相x,即消息预订者未ȀzM可以接收到消息。此外,使用持久订阅q可通过队列提供灉|性和可靠性,而仍然允许消息被发给许多的接收者?Topic Subscriber topic Subscriber = topicSession.createDurableSubscriber(topic, subscriptionName); Connection对象表示了到两种消息模型中的MU的消息pȝ的连接。服务器端和客户机端对象要求理创徏的JMSq接的状态。连接是由Connection Factory创徏的ƈ且通过JNDI查寻定位?//取得用于 P2P?QueueConnectionFactory QueueConnectionFactory = queueConnectionFactory( ); Context messaging = new InitialContext( ); QueueConnectionFactory = (QueueConnectionFactory) Messaging.lookup(“QueueConnectionFactory”); //取得用于 pub/sub?TopicConnectionFactory TopicConnectonFactory topicConnectionFactory; Context messaging = new InitialContext(); topicConnectionFactory = (TopicConnectionFactory) messaging.lookup(“TopicConnectionFactory”); 注意Q用于P2P的代码和用于PublishSubscribe的代码非常相伹{?/font> 如果session被标Cؓtransactional的话Q确认消息就通过认和校正来自动地处理。如果session没有标记?transactionalQ你有三个用于消息确认的选项?/font> · AUTO_ACKNOWLEDGE session自动地认收到一则消息?/font> · CLIENT_ACKNOWLEDGE 客户?/font>E序确认收C则消息,调用q则消息的确认方法? · DUPS_OK_ACKNOWLEDGE q个选项命osession“懒散?#8221;认消息传递,可以惛_Q这导致消息提供者传递的一些复制消息可能会出错。这U确认的方式只应当用于消息消费程序可以容忍潜在的副本消息存在的情c?queueSession = queueConnection.createQueueSession(false, session.AUTO_ACKNOWLEDGE);//P2P topicSession = topicConnection.createTopicSession(false, session.AUTO_ACKNOWLEDGE); //Pub-Sub 注意Q在本例中,一个session目的从连l中创徏Q非值指出session是non-transactional的,q且 session自动地认收到一则消息?/font> JMS现在有两U传递消息的方式。标CؓNON_PERSISTENT的消息最多投递一ơ,而标CؓPERSISTENT的消息将使用暂存后再转送的机理投递。如果一个JMS服务ȝQ那么持久性消息不会丢׃是得{到q个服务恢复联机时才会被传递。所以默认的消息传递方式是非持久性的。即使用非持久性消息可能降低内务和需要的存储器,q且q种传递方式只有当你不需要接收所有的消息时才使用?/font> 虽然 JMS规范q不需要JMS供应商实现消息的优先U\U,但是它需要递送加快的消息优先于普通别的消息。JMS定义了从0?的优先路线U别Q?是最低的优先U?则是最高的。更Ҏ的是0?是正怼先的变化幅度,??是加快的优先U的变化q度。D例来_ topicPublisher.publish (message, DeliveryMode.PERSISTENT, 8, 10000); //Pub-Sub ?queueSender.send(message, DeliveryMode.PERSISTENT, 8, 10000);//P2P q个代码片断Q有两种消息模型Q映递送方式是持久的,优先Uؓ加快型,生存周期?0000 (以毫U?a target=_new>度量 )。如果生存周期设|ؓӞq则消息永q不会过期。当消息需要时间限制否则将使其无效Ӟ讄生存周期是有用的?/font> JMS定义了五U不同的消息正文格式Q以及调用的消息cdQ允怽发送ƈ接收以一些不同Ş式的数据Q提供现有消息格式的一些别的兼容性?/font> · StreamMessage -- Java原始值的数据? · MapMessage--一套名U?值对 · TextMessage--一个字W串对象 · ObjectMessage--一个序列化?Java对象 · BytesMessage--一个未解释字节的数据流 JMS应用E序接口提供用于创徏每种cd消息和设|荷载的Ҏ例如Qؓ了在一个队列创建ƈ发送一个TextMessage实例Q你可以使用下列语句Q?TextMessage message = queueSession.createTextMessage(); message.setText(textMsg); 以异步方式接收消息,需要创Z个消息监听器然后注册一个或多个使用MessageConsumer的JMS MessageListener接口。会?主题或队?负责产生某些消息Q这些消息被传送到使用onMessageҎ的监听者那里?import javax.jms.*; public class ExampleListener implements MessageListener { //把消息强制{化ؓTextMessage格式 public void onMessage(Message message) { TextMessage textMsg = null; // 打开q处理这D|?} } 当我们创建QueueReceiver和TopicSubscriberӞ我们传递消息选择器字W串Q?//P2P QueueReceiver QueueReceiver receiver; receiver = session.createReceiver(queue, selector); //Pub-Sub TopicSubscriber TopicSubscriber subscriber; subscriber = session.createSubscriber(topic, selector); Z启动消息的交付,不论是Pub/Subq是P2PQ都需要调用startҎ?TopicConnection.start( ); //pub-sub QueueConnection.start( ); //P2P TopicConnection.start ( );// pub-sub QueueConnection.start ( );// P2P 当一条消息被捕捉Ӟq条消息做ؓ一条必被强制转化为适当消息cd的普通Message对象到达。这是一个被用来提取或打开消息内容的getterҎ。下列代码片D用StreamMessagecd?private void unPackMessage (Message message) { String eName; String position; double rate; StreamMessage message; Message = session.createStreamMessage( ); //注意下面的代码必L照我l出的顺序书?message.writeString(eName); message.writeString(position); message.writeDouble(rate); //实现处理消息的必要的E序逻辑 } 停止消息的传递,无论是Pub/Subq是P2PQ都调用stopҎ?TopicConnection.start( ); //pub-sub QueueConnection.start( ); //P2P TopicConnection.start ( );// pub-sub QueueConnection.start ( );// P2P 其他?a target=_new>J2EElg--servlet或EJB--可以当作消息生者;然而,它们可能只能同步操作Q这可能是因为它们的h-应答的性质军_的。虽?a target=_new>XML目前q不是被支持的消息类型,发送一个XML文g和创Z条文本类型消息以及把XML文gd到消息的有效负蝲都一L单,都是以非专有的方式传送数据。值得注意的是Q一些JMS供应厂商已经提供了可用的XML消息cd。但是用非标准的消息类型可能会出现可移植性问题?String reportData; //reportData内容为XML 文 TextMessage message; message = session.createTextMessage(); message.setText (reportData); 消息驱动lg(MDB)是一个当消息到达时被容器调用的异步消息消费程序。和entity和session EJB不同QMDB没有本地和远E接口ƈ且是匿名的;它们对于客户是不可见的。MDB是JMSpȝ的一部分Q作为消费者实现服务器上的商业逻辑E序?一个客L序可能通过使用JNDI定位一个与MDB相关联的JMS?例如Q?Context initialContext = new InitialContext(); Queue reportInfoQueue = (javax.jms.Queue)initialContext.lookup (“java:comp/env/jms/reportInfoQueue”); MDB是由Beancd相应的XML部v描述W组成?Bean cd现MessageDriveBean 接口Q?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( ); } 部v描述W?Q?DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN" "http://java.sun.com/j2ee/dtds/ejb-jar_2_0.dtd"Q?Qejb-jarQ?Qenterprise-beansQ?Qmessage-drivenQ?Qejb-nameQMDBQ?ejb-nameQ?Qejb-classQMDBQ?ejb-classQ?Qtransaction-typeQContainerQ?transaction-typeQ?Qmessage-driven-destinationQ?Qjms-destination-typeQjavax.jms.QueueQ?jms-destination-typeQ?Q?message-driven-destinationQ?Qsecurity-identityQ?Qrun-as-specified-identityQ?Qrole-nameQeveryoneQ?role-nameQ?Q?run-as-specified-identityQ?Q?security-identityQ?Q?message-drivenQ?Q?enterprise-beansQ?Q?ejb-jarQ?/font> 既然我们现在已经有了一些基本的JMS知识Q那么我们可以用JMS做什么呢QQ何事情都可以?/font> 例如Q分别用于销售、库存、客h务和账目处理的系l。这些部门之间的pȝ很可能已l存在了很长旉Q这些处理要求把事务Ud到系l中去,qƈ不是一个小的工作。这是消息服务适用的地炏V?/font> 当售货员完成销售的时候,一条消息被发给库存pȝQ一旦订单消息发送给收发货h员,可以按照订单出货了。当订单成功地发货,pȝ通知֮服务和会计系l这个订单已l成功的交易了。所有对应的每个子系l?/font>都自动地Ҏ收到的消息进行更新?/font> JMS一般都不是用来整合一个系l,而是整合许多可能参与消息驱动环境的系l。JMS是一个用于开发和集成企业应用E序的重要的工具。因多公叔R有以前遗留下来的pȝ和新q开发的pȝl合h的系l,消息的用是整合整个企业的重要的步骤? JMS接口描述 JMS 支持两种消息cdPTP 和Pub/SubQ分别称作:PTP Domain 和Pub/Sub DomainQ这两种接口都承统一的JMS Parent 接口QJMS 主要接口如下所C:
JMS 使您能够通过消息收发服务Q有时称为消息中介程序或路由器)从一?JMS 客户机向另一?JML 客户机发送消息。消息是 JMS 中的一U?/font>cd对象Q由两部分组成:报头和消息主体。报头由路由信息以及有关该消息的元数?/u>l成。消息主体则携带着应用E序的数据或有效负蝲。根据有效负载的cd来划分,可以消息分为几U类型,它们分别携带Q简单文?(TextMessage)、可序列化的对象 (ObjectMessage)、属性集?(MapMessage)、字节流 (BytesMessage)、原始值流 (StreamMessage)Q还有无有效负蝲的消?(Message)?
JMS Parent
PTPDomain
Pub/Sub Domain
ConnectionFactory
QueueConnectionFactory
TopicConnectionFactory
Connection
QueueConnection
TopicConnection
Destination
Queue
Topic
Session
QueueSession
TopicSession
MessageProducer
QueueSender
TopicPublisher
MessageConsumer
QueueReceiver,QueueBrowser
TopicSubscriber
以下是对q些接口的简单描qͼ
ConnectionFactory Q连接工厂,JMS 用它创徏q接
Connection QJMS 客户端到JMS Provider 的连?br> Destination Q消息的目的?br> SessionQ?一个发送或接收消息?a target=_new>U程
MessageProducerQ?由Session 对象创徏的用来发送消息的对象
MessageConsumerQ?由Session 对象创徏的用来接收消息的对象
JMS消息模型
JMS 消息׃下几部分l成Q消息头Q属性,消息体?/font>
消息?Header) - 消息头包含消息的识别信息和\׃息,消息头包含一些标准的属性如QJMSDestination,JMSMessageID {?
消息?/em>
p讄
JMSDestination
send ?publish Ҏ
JMSDeliveryMode
send ?publish Ҏ
JMSExpiration
send ?publish Ҏ
JMSPriority
send ?publish Ҏ
JMSMessageID
send ?publish Ҏ
JMSTimestamp
send ?publish Ҏ
JMSCorrelationID
客户
JMSReplyTo
客户
JMSType
客户
JMSRedelivered
JMS Provider
消息?Body) - JMS API 定义?U消息体格式Q也叫消息类型,你可以用不同Ş式发送接收数据ƈ可以兼容现有的消息格式,下面描述q?U类型:
属?Properties) - 除了消息头中定义好的标准属性外QJMS 提供一U机制增加新属性到消息头中Q这U新属性包含以下几U:
1. 应用需要用到的属?
2. 消息头中原有的一些可选属?
3. JMS Provider 需要用到的属性?br> 标准的JMS 消息头包含以下属性:
JMSDestination --消息发送的目的?
JMSDeliveryMode --传?a target=_new>模式Q?有两U模式: PERSISTENT 和NON_PERSISTENTQPERSISTENT 表示该消息一定要被送到目的圎ͼ否则会导致应用错误。NON_PERSISTENT 表示偶然丢失该消息是被允许的Q这两种模式使开发者可以在消息传递的可靠性和吞吐量之间找到^衡点?br> JMSMessageID 唯一识别每个消息的标识,由JMS Provider 产生?br> JMSTimestamp 一个消息被提交lJMS Provider 到消息被发出的时间?br> JMSCorrelationID 用来q接到另外一个消息,典型的应用是在回复消息中q接到原消息?br> JMSReplyTo 提供本消息回复消息的目的地址?br> JMSRedelivered 如果一个客L收到一个设|了JMSRedelivered 属性的消息Q则表示可能该客L曄在早些时候收到过该消息,但ƈ没有{收(acknowledged)?br> JMSType 消息cd的识别符?br> JMSExpiration 消息q期旉Q等于QueueSender 的send Ҏ中的timeToLive 值或TopicPublisher 的publish Ҏ中的timeToLive 值加上发送时ȝGMT 旉倹{如果timeToLive值等于零Q则JMSExpiration 被设为零Q表C消息怸q期。如果发送后Q在消息q期旉之后消息q没有被发送到目的圎ͼ则该消息被清除?br> JMSPriority 消息优先U,?-9 十个U别Q?-4 是普通消息,5-9 是加急消息。JMS 不要求JMS Provider 严格按照q十个优先发送消息,但必M证加急消息要先于普通消息到达?/p>
消息cd
消息?/em>
TextMessage
java.lang.String对象Q如xml文g内容
MapMessage
?值对的集合,名是String对象Q值类型可以是JavaM基本cd
BytesMessage
字节?/td>
StreamMessage
Java中的输入输出?/td>
ObjectMessage
Java中的可序列化对象
Message
没有消息体,只有消息头和属性?/td>
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 }