日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

Jms基礎(chǔ)知識(shí)整理

 nbtymm 2007-03-23

開始文章之前先澄清幾個(gè)概念

什么是消息

消息是一個(gè)用于在組件和應(yīng)用程序之間通訊的的方法。消息之間的傳遞是點(diǎn)對(duì)點(diǎn)的。任何終端之間都可以相互接受和發(fā)送消息。并且每個(gè)終端都必須遵守如下的規(guī)則
 -> 創(chuàng)建消息 -> 發(fā)送消息 -> 接收消息 -> 讀取消息

為什么要使用消息
理由很簡單,消息是一個(gè)分布式的低耦合通訊方案。A發(fā)送一個(gè)消息到一個(gè)agent ,B作為接受者去agent上獲取消息。但是A,B不需要同時(shí)到agent上去注冊(cè)。agent作為一個(gè)中轉(zhuǎn)為A,B提供搞效率的通訊服務(wù)。

開發(fā)者的關(guān)注點(diǎn)
走到這里,我也不想去解釋jms spec上那些抽象且復(fù)雜的概念了,說的很白,1年多了我自己也沒弄懂是個(gè)什么東西,也沒時(shí)間從頭到尾去仔細(xì)的看,同時(shí)我認(rèn)為沒必要,我所關(guān)注的是如何讓jms跑起來,并且工作正常,所以spec只是個(gè)字典,當(dāng)我需要用的時(shí)候才去查。

開發(fā)者的jms環(huán)境
遵守簡單明了的原則,所謂jms環(huán)境只是2個(gè)對(duì)象
1> ConnectionFactory
2> Destination

通常Provider會(huì)提供JNDI的對(duì)象獲取,具體方法可以去Privider的網(wǎng)站上搜索jndi support

下面我以jbossMq為介質(zhì)跑一個(gè)簡單的jms,為了保證jms的本質(zhì)清晰,我沒有使用jbossMq的Api,而是直接調(diào)用的jms Api.
java 代碼
 
  1. package com.javaeye.jms.jboss;  
  2.   
  3. import javax.jms.Connection;  
  4. import javax.jms.ConnectionFactory;  
  5. import javax.jms.Destination;  
  6. import javax.jms.JMSException;  
  7. import javax.jms.MessageConsumer;  
  8. import javax.jms.MessageProducer;  
  9. import javax.jms.Queue;  
  10. import javax.jms.QueueSender;  
  11. import javax.jms.Session;  
  12. import javax.jms.TextMessage;  
  13. import javax.naming.Context;  
  14. import javax.naming.InitialContext;  
  15. import javax.naming.NamingException;  
  16.   
  17. public class JbossNativeJmsImpl {  
  18.      
  19.     /** 
  20.      * @author zuly 
  21.      * 
  22.      * following jms ptp domain, use an simple text message to test 
  23.      * 
  24.      * A jms ptp sender will following the steps below! 
  25.      *     1> get an ConnectionFactory use JNDI Lookup Or Initial it yourself 
  26.      *     2> use this ConnectionFactory to start a jms connection
  27.      *        [spec to jms 1.1 apito get the main idea of it ] 
  28.      *     3> use connection to create a jms session 
  29.      *     4> get a queue destination / messege agent 
  30.      *     5> start the Producer[jms1.1 spec] by a session 
  31.      *     6> get messege Object or initial it yourself by implements the messegeor 
  32.      *        it‘s sub interfaces 
  33.      *     7> call sender or send it selfing 
  34.      *     8> finallized the connection object or it will throw a warning to you! 
  35.      * 
  36.      * @param messege 
  37.      * @throws NamingException 
  38.      * @throws JMSException 
  39.      */  
  40.     public void sendingProcessing(String messege) throws NamingException, JMSException{  
  41.         Context ctx = new InitialContext();  
  42.         ConnectionFactory cf = (ConnectionFactory) ctx.lookup("java:JmsXA");  
  43.         Connection conn = cf.createConnection();  
  44.         Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);  
  45.         Destination dest = (Queue) ctx.lookup("queue/A");  
  46.         MessageProducer msgp = session.createProducer(dest);  
  47.         QueueSender sender = (QueueSender) msgp;  
  48.         TextMessage msg = session.createTextMessage();  
  49.         msg.setText(messege);  
  50.         sender.send(msg);  
  51.         conn.close();  
  52.     }  
  53.      
  54.      
  55.      
  56.     /** 
  57.      * @author zuly 
  58.      * 
  59.      * following jms ptp domain, use an simple text message to test 
  60.      * 
  61.      * A jms ptp retriver will following the steps below! 
  62.      *     1> get an ConnectionFactory use JNDI Lookup Or Initial it yourself 
  63.      *     2> use this ConnectionFactory to start a jms connection 
  64.      *        [spec to jms 1.1 api to get the main idea of it ] 
  65.      *     3> use connection to create a jms session 
  66.      *     4> get a queue destination / messege agent 
  67.      *     5> retrive a consumer from session 
  68.      *     6> start the jms connection to retrivte the message 
  69.      *     7> get message from consumer 
  70.      *  
  71.      * @return textMessege 
  72.      * @throws NamingException 
  73.      * @throws JMSException 
  74.      */  
  75.     public String retriveingProcessing() throws NamingException, JMSException{  
  76.         Context ctx = new InitialContext();  
  77.         ConnectionFactory cf = (ConnectionFactory) ctx.lookup("java:JmsXA");  
  78.         Connection conn = cf.createConnection();  
  79.         Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);  
  80.         Destination dest = (Queue) ctx.lookup("queue/A");  
  81.         MessageConsumer msgconsumer = session.createConsumer(dest);  
  82.         //MessageListener ml = new JmsListenner();  
  83.         //msgconsumer.setMessageListener(ml);  
  84.         conn.start();  
  85.         TextMessage msg = (TextMessage) msgconsumer.receive();  
  86.         conn.close();  
  87.         System.out.println("messege is" + msg.getText());  
  88.         return msg.getText();  
  89.     }  
  90. }  


注意retrive函數(shù)中comment的掉的兩行,消息Listener的作用是實(shí)現(xiàn)異步通訊,但是它有一個(gè)約定,必須和發(fā)送者
保持物理上的分離,針對(duì)于jboss而言,就要求這個(gè)Listener必須跑在容器外面。這是一個(gè)很搞的問題,每天Jms的郵件列表里面都有無數(shù)的這樣的問題發(fā)過來。但是回復(fù)的人很少。我自己也從來不回復(fù)。 其實(shí)我也不清楚寫這篇文章到底是出于什么目的,怕只是讓這么一個(gè)簡單的問題有一個(gè)回答而已。

把下面這個(gè)程序跑起來就可以異步接受消息了。

java 代碼
 
  1. package com.javaeye.jms.jboss;  
  2.   
  3. import java.util.Properties;  
  4.   
  5. import javax.jms.Connection;  
  6. import javax.jms.ConnectionFactory;  
  7. import javax.jms.Destination;  
  8. import javax.jms.JMSException;  
  9. import javax.jms.MessageConsumer;  
  10. import javax.jms.MessageListener;  
  11. import javax.jms.Session;  
  12. import javax.naming.Context;  
  13. import javax.naming.InitialContext;  
  14. import javax.naming.NamingException;  
  15.   
  16. import com.javaeye.spring.services.jms.mdp.JmsListenner;  
  17.   
  18. public class JbossJmsAsync {  
  19.   
  20.     /** 
  21.      * @param args 
  22.      * @throws NamingException  
  23.      * @throws JMSException  
  24.      */  
  25.     public static void main(String[] args) throws NamingException, JMSException {  
  26.         Properties pops = new Properties();  
  27.         pops.setProperty("jboss.bind.address""0.0.0.0");  
  28.         pops.setProperty("java.naming.factory.initial""org.jnp.interfaces.NamingContextFactory");  
  29.         pops.setProperty("java.naming.factory.url.pkgs""org.jboss.naming:org.jnp.interfaces");  
  30.         pops.setProperty("java.naming.provider.url""localhost");  
  31.         Context ctx = new InitialContext(pops);  
  32.         ConnectionFactory cf = (ConnectionFactory) ctx.lookup("ConnectionFactory");  
  33.         Connection conn = cf.createConnection();  
  34.         Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);  
  35.         Destination dest = (Destination) ctx.lookup("queue/A");  
  36.         MessageConsumer msgConsumer = session.createConsumer(dest);  
  37.         MessageListener ml = new JmsListenner();  
  38.         msgConsumer.setMessageListener(ml);   
  39.         conn.start();  
  40.     }  
  41.   
  42. }  


javaeye的主題好像是spring,為了迎合領(lǐng)導(dǎo),下面我把這套東西跑在spring里面。同時(shí)我發(fā)現(xiàn)spring對(duì)jms的包裝真的簡單,而且還提供了一個(gè)模版,雖然這個(gè)模版的接口是在是很羅唆。

ps:今天是第1次用spring在reference里找了半天找不到方法注入的辦法,于是google了一個(gè)注入辦法,不合理的地方請(qǐng)大家指出。首先我通過方法來注入ConnectionFactory和Destination這兩個(gè)對(duì)象來支撐jms環(huán)境

java 代碼
 
  1. package com.javaeye.spring.services.jms.mdp;  
  2.   
  3. import java.util.Properties;  
  4.   
  5. import javax.jms.ConnectionFactory;  
  6. import javax.jms.Destination;  
  7. import javax.jms.Queue;  
  8. import javax.naming.Context;  
  9. import javax.naming.InitialContext;  
  10. import javax.naming.NamingException;  
  11.   
  12. public class UserJmsTransactionUtil {  
  13.   
  14.     private String connectionFactoryJndiLookUp;  
  15.      
  16.     private String destinationJndiLookUp;  
  17.      
  18.     private String localConnectionFactoryJndiLookUp;  
  19.      
  20.     private String containerType;  
  21.      
  22.      
  23.     public String getConnectionFactoryJndiLookUp() {  
  24.         return connectionFactoryJndiLookUp;  
  25.     }  
  26.   
  27.   
  28.   
  29.     public void setConnectionFactoryJndiLookUp(String connectionFactoryJndiLookUp) {  
  30.         this.connectionFactoryJndiLookUp = connectionFactoryJndiLookUp;  
  31.     }  
  32.   
  33.   
  34.   
  35.     public String getDestinationJndiLookUp() {  
  36.         return destinationJndiLookUp;  
  37.     }  
  38.   
  39.   
  40.   
  41.     public void setDestinationJndiLookUp(String destinationJndiLookUp) {  
  42.         this.destinationJndiLookUp = destinationJndiLookUp;  
  43.     }  
  44.   
  45.   
  46.   
  47.     public ConnectionFactory getConnectionFactory() throws NamingException{  
  48.         Context ctx = new InitialContext();  
  49.         ConnectionFactory cf = (ConnectionFactory) ctx.lookup(connectionFactoryJndiLookUp);  
  50.         return cf;  
  51.     }  
  52.      
  53.      
  54.     public Destination getJmsDestination() throws NamingException{  
  55.         Context ctx = new InitialContext();  
  56.         Destination dest = (Queue) ctx.lookup(destinationJndiLookUp);  
  57.         return dest;  
  58.     }  
  59.      
  60.      
  61.     public ConnectionFactory getQueueConnectionFactory() throws NamingException{  
  62.         Properties pops = new Properties();  
  63.         pops.setProperty("jboss.bind.address""0.0.0.0");  
  64.         pops.setProperty("java.naming.factory.initial""org.jnp.interfaces.NamingContextFactory");  
  65.         pops.setProperty("java.naming.factory.url.pkgs""org.jboss.naming:org.jnp.interfaces");  
  66.         pops.setProperty("java.naming.provider.url""localhost");  
  67.         Context ctx = new InitialContext(pops);  
  68.         ConnectionFactory cf = (ConnectionFactory) ctx.lookup(localConnectionFactoryJndiLookUp);  
  69.         return cf;  
  70.     }  
  71.      
  72.      
  73.     public Destination getLocalJmsDestination() throws NamingException{  
  74.         Properties pops = new Properties();  
  75.         pops.setProperty("jboss.bind.address""0.0.0.0");  
  76.         pops.setProperty("java.naming.factory.initial""org.jnp.interfaces.NamingContextFactory");  
  77.         pops.setProperty("java.naming.factory.url.pkgs""org.jboss.naming:org.jnp.interfaces");  
  78.         pops.setProperty("java.naming.provider.url""localhost");  
  79.         Context ctx = new InitialContext(pops);  
  80.         Destination dest = (Destination) ctx.lookup(destinationJndiLookUp);  
  81.         return dest;  
  82.     }  
  83.   
  84.   
  85.   
  86.     public String getLocalConnectionFactoryJndiLookUp() {  
  87.         return localConnectionFactoryJndiLookUp;  
  88.     }  
  89.   
  90.   
  91.   
  92.     public void setLocalConnectionFactoryJndiLookUp(  
  93.             String localConnectionFactoryJndiLookUp) {  
  94.         this.localConnectionFactoryJndiLookUp = localConnectionFactoryJndiLookUp;  
  95.     }     
  96. }

發(fā)送端的配置如下

xml 代碼
 
  1. <beans>  
  2.     <bean id="userJmsUtil" class="com.javaeye.spring.services.jms.mdp.UserJmsTransactionUtil">  
  3.         <property name="connectionFactoryJndiLookUp" value="java:JmsXA"><!--</span-->property>  
  4.         <property name="destinationJndiLookUp" value="queue/A"><!--</span-->property>  
  5.         <property name="localConnectionFactoryJndiLookUp" value="ConnectionFactory"><!--</span-->property>  
  6.     <!--</span-->bean>  
  7.   
  8.     <bean id="connectionFactory" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">  
  9.         <property name="targetObject" ref="userJmsUtil"><!--</span-->property>  
  10.         <property name="targetMethod" value="getConnectionFactory"><!--</span-->property>  
  11.     <!--</span-->bean>  
  12.       
  13.     <bean id="queue" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">  
  14.         <property name="targetObject" ref="userJmsUtil"><!--</span-->property>  
  15.         <property name="targetMethod" value="getJmsDestination"><!--</span-->property>  
  16.     <!--</span-->bean>  
  17.           
  18.     <bean id="jmsQueue" class="org.springframework.jms.core.JmsTemplate">  
  19.         <property name="connectionFactory" ref="connectionFactory"><!--</span-->property>  
  20.         <property name="defaultDestination" ref="queue"><!--</span-->property>  
  21.         <property name="messageConverter">  
  22.             <bean class="org.springframework.jms.support.converter.SimpleMessageConverter"><!--</span-->bean>  
  23.         <!--</span-->property>  
  24.     <!--</span-->bean>  
  25. <!--</span-->beans>  

ps:javaeye的模版工具bug還真多,不管了.

如果使用Listenner的化,一樣需要遵守發(fā)送者和接收者物理隔離的原則,我的做法是把發(fā)送者配到一個(gè)xml中,在把接受者配到另外一個(gè)xml中去,發(fā)送的配置綁定到容器里,接收者的跑在本地.否則spring初始化是過不去的.

下面這個(gè)程序是發(fā)送消息的程序.使用了spring的模版,發(fā)條消息比new個(gè)對(duì)象還簡單.同時(shí)spring還提供了適配器的接口,一樣通過聲明式的配置,這樣可以在同一個(gè)接口里發(fā)送各種類型的消息了.同時(shí)支持事務(wù),我還不知道這個(gè)有什么用呵呵,第1次使用嘛!但是就使用上來說,spring是最簡單的.2者都只需要注入一個(gè)對(duì)象而已.

java 代碼
 
  1. @Test public void send(){  
  2.     ApplicationContext ac = new FileSystemXmlApplicationContext("jms.xml");  
  3.     BeanFactory bf = ac;  
  4.     JmsTemplate jt = (JmsTemplate) bf.getBean("jmsQueue");  
  5.     jt.convertAndSend("2132134");  
  6. }  


接收端的配置如下
xml 代碼
 
  1. xml version="1.0" encoding="UTF-8"?>  
  2. >  
  3. <beans>  
  4.   
  5.     <bean id="listenner" class="com.javaeye.spring.services.jms.mdp.JmsListenner"><!--</span-->bean>  
  6.       
  7.     <bean id="userJmsUtil" class="com.javaeye.spring.services.jms.mdp.UserJmsTransactionUtil">  
  8.         <property name="connectionFactoryJndiLookUp" value="java:JmsXA"><!--</span-->property>  
  9.         <property name="destinationJndiLookUp" value="queue/A"><!--</span-->property>  
  10.         <property name="localConnectionFactoryJndiLookUp" value="ConnectionFactory"><!--</span-->property>  
  11.     <!--</span-->bean>  
  12.   
  13.     <bean id="localConnectionFactory" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">  
  14.         <property name="targetObject" ref="userJmsUtil"><!--</span-->property>  
  15.         <property name="targetMethod" value="getQueueConnectionFactory"><!--</span-->property>  
  16.     <!--</span-->bean>  
  17.       
  18.     <bean id="localDestination" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">  
  19.         <property name="targetObject" ref="userJmsUtil"><!--</span-->property>  
  20.         <property name="targetMethod" value="getLocalJmsDestination"><!--</span-->property>  
  21.     <!--</span-->bean>  
  22.       
  23.     <bean id="listenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">  
  24.         <property name="concurrentConsumers" value="5"><!--</span-->property>  
  25.         <property name="connectionFactory" ref="localConnectionFactory"><!--</span-->property>  
  26.         <property name="destination" ref="localDestination"><!--</span-->property>  
  27.         <property name="messageListener" ref="listenner"><!--</span-->property>  
  28.     <!--</span-->bean>  
  29. <!--</span-->beans>  


接收端由于需要從jbossmq里取ConnectionFactory和Destination,所以,我調(diào)用的是userJmsUtil的localLookup.這個(gè)函數(shù)的作用等同于發(fā)送者的那個(gè)函數(shù),只不過前者是容器外獲取,而后者是容器內(nèi)的而已.

java 代碼
 
  1. package com.javaeye.spring.services.jms.mdp;  
  2.   
  3. import javax.jms.JMSException;  
  4. import javax.jms.Message;  
  5. import javax.jms.MessageListener;  
  6. import javax.jms.TextMessage;  
  7.   
  8. public class JmsListenner implements MessageListener {  
  9.   
  10.     public void onMessage(Message message) {  
  11.         try {  
  12.             TextMessage msg = (TextMessage) message;  
  13.             System.out.println(msg.getText());  
  14.         } catch (JMSException e) { e.printStackTrace(); }  
  15.     }  
  16.   


spring對(duì)jms的整合里提到了一個(gè)jms provider ActiveMQ,要用一個(gè)開源框架要做的第一件事就是先跑一個(gè)demo起來,同樣,我們要做的事還是獲取ConnectionFactory和Destination對(duì)象,還好,ActiveMQ的JNDI實(shí)現(xiàn)比jbossMQ還要簡單,直接通過一個(gè)本地的Context就可以查到了,具體的可以參照ActiveMQ官方的支持文檔.

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多