<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    轉(zhuǎn):用Spring快速開發(fā)jms應(yīng)用(JBOSS服務(wù)器)

    異步進程通信是面向服務(wù)架構(gòu)(SOA)一個重要的組成部分,因為企業(yè)里很多系統(tǒng)通信,特別是與外部組織間的通信,實質(zhì)上都是異步的。Java消息服務(wù)(JMS)是用于編寫使用異步消息傳遞的JEE應(yīng)用程序的API。傳統(tǒng)的使用JMS API進行消息傳遞的實現(xiàn)包括多個步驟,例如JNDI查詢隊列連接工廠和Queue資源,在實際發(fā)送和接收消息前創(chuàng)建一個JMS會話。

       Spring框架則簡化了使用JEE組件(包括JMS)的任務(wù)。它提供的模板機制隱藏了典型的JMS實現(xiàn)的細(xì)節(jié),這樣開發(fā)人員可以集中精力放在處理消息的實際工作中,而不用擔(dān)心如何去創(chuàng)建,訪問或清除JMS資源。

       本文將對Spring JMS API作一個概述,并通過一個運行在JBoss MQ服務(wù)器上的web例程來介紹如何使用Spring JMS API來異步處理(發(fā)送和接收)消息。我將通過傳統(tǒng)JMS實現(xiàn)和Spring JMS實現(xiàn)兩者間的比較,來展示使用Spring JMS處理消息是如何的簡單和靈活。

    異步消息傳遞和面向服務(wù)架構(gòu)

      在現(xiàn)實中,大多數(shù)web請求都是同步處理的。例如,當(dāng)用戶要登入一個網(wǎng)站,首先輸入用戶名和密碼,然后服務(wù)器驗證登錄合法性。如果驗證成功,程序?qū)⒃试S該用戶進入網(wǎng)站。這里,登錄請求在從客戶端接收以后被即時處理了。信用卡驗證是另一個同步處理的例子;只有服務(wù)器證實輸入的信用卡號是有效的,同時客戶在帳戶上有足夠的存款,客戶才被允許繼續(xù)操作。但是讓我們思考一下在順序處理系統(tǒng)上的支付結(jié)算步驟。一旦系統(tǒng)證實該用戶信用卡的信息是準(zhǔn)確的,并且在帳戶上有足夠的資金,就不必等到所有的支付細(xì)節(jié)落實、轉(zhuǎn)賬完成。支付結(jié)算可以異步方式進行,這樣客戶可以繼續(xù)進行核查操作。

       需要比典型同步請求耗費更長時間的請求,可以使用異步處理。另一個異步處理的例子是,在本地貸款處理程序中,提交至自動承銷系統(tǒng)(AUS)的信用請求處理過程。當(dāng)借方提交貸款申請后,抵押公司會向AUS發(fā)送請求,以獲取信用歷史記錄。由于這個請求要求得到全面而又詳細(xì)的信用報告,包括借方現(xiàn)今和過去的帳戶,最近的付款和其他財務(wù)資料,服務(wù)器需要耗費較長的時間(幾小時或著有時甚至是幾天)來對這些請求作出響應(yīng)。客戶端程序(應(yīng)用)要與服務(wù)器連接并耗費如此長的時間來等待結(jié)果,這是毫無意義的。因此通信應(yīng)該是異步發(fā)生的;也就是,一旦請求被提交,它就被放置在隊列中,同時客戶端與服務(wù)器斷開連接。然后AUS服務(wù)從指定的隊列中選出請求進行處理,并將處理得到的消息放置在另一個消息隊列里。最后,客戶端程序從這個隊列中選出處理結(jié)果,緊接著處理這個信用歷史數(shù)據(jù)。

    JMS

       如果您使用過JMS代碼,您會發(fā)現(xiàn)它與JDBC或JCA很像。它所包含的樣本代碼創(chuàng)建或JMS資源對象回溯,使得每一次您需要寫一個新類來發(fā)送和接收消息時,都具有更好的代碼密集性和重復(fù)性。以下序列顯示了傳統(tǒng)JMS實現(xiàn)所包括的步驟:

    1. 創(chuàng)建JNDI初始上下文(context)。
    2. 從JNDI上下文獲取一個隊列連接工廠。
    3. 從隊列連接工廠中獲取一個Quene。
    4. 創(chuàng)建一個Session對象。
    5. 創(chuàng)建一個發(fā)送者(sender)或接收者(receiver)對象。
    6. 使用步驟5創(chuàng)建的發(fā)送者或接收者對象發(fā)送或接收消息。
    7. 處理完消息后,關(guān)閉所有JMS資源。

    您可以看到,步驟6是處理消息的唯一地方。其他步驟都只是管理與實際業(yè)務(wù)要求無關(guān)的JMS資源,但是開發(fā)人員必須編寫并維護這些額外步驟的代碼。

    Spring JMS

       Spring框架提供了一個模板機制來隱藏Java APIs的細(xì)節(jié)。JEE開發(fā)人員可以使用JDBCTemplate和JNDITemplate類來分別訪問后臺數(shù)據(jù)庫和JEE資源(數(shù)據(jù)源,連接池)。JMS也不例外。Spring提供JMSTemplate類,因此開發(fā)人員不用為一個JMS實現(xiàn)去編寫樣本代碼。接下來是在開發(fā)JMS應(yīng)用程序時Spring所具有一些的優(yōu)勢。

    1. 提供JMS抽象API,簡化了訪問目標(biāo)(隊列或主題)和向指定目標(biāo)發(fā)布消息時JMS的使用。
    2. JEE開發(fā)人員不需要關(guān)心JMS不同版本(例如JMS 1.0.2與JMS 1.1)之間的差異。
    3. 開發(fā)人員不必專門處理JMS異常,因為Spring為所有JMS異常提供了一個未經(jīng)檢查的異常,并在JMS代碼中重新拋出。

    示例程序

            說明:因為只是為了演示如何使用spring編寫jms的應(yīng)用,所以本例沒有什么實際用途。

            程序功能:MessageProducer.java根據(jù)一用戶信息產(chǎn)生一個消息發(fā)送到 JMS Provider;由MessageConsumer.java接收。

    1.在Jboss里配置XML文件創(chuàng)建一個新的JMS provider。
    打開位于%JBOSS_HOME%server\default\deploy\jms文件夾下的jbossmq-destinations-service.xml文件,加入以下代碼片斷:
     <!--  Register User Send/Receive Queue  -->
     <mbean code="org.jboss.mq.server.jmx.Queue"
       name="jboss.mq.destination:service=Queue,name=registerUserQueue">
       <depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>
     </mbean>
     <!--  Register User Send/Receive Topic  -->
     <mbean code="org.jboss.mq.server.jmx.Topic"
      name="jboss.mq.destination:service=Topic,name=registerUserTopic">
       <depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>
     </mbean>
    2.在spring的配置文件中配置JMS組件的具體細(xì)節(jié)。
     (1)JNDI上下文是取得JMS資源的起始位置,因此首先我們要配置JNDI模板:
        <!-- JNDI上下文(它是取得JMS資源的起始位置) -->
       <bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
        <property name="environment">
         <props>
          <prop key="java.naming.factory.initial">
           org.jnp.interfaces.NamingContextFactory
          </prop>
          <prop key="java.naming.provider.url">localhost</prop>
          <prop key="java.naming.factory.url.pkgs">
           org.jnp.interfaces:org.jboss.naming
          </prop>
         </props>
        </property>
       </bean>
       注意:此JNDI模板用到了org.jnp.interfaces.NamingContextFactory所以要把%JBOSS_HOME%\client下的jbossall-client.jar加到你的項目的classpath中。
    (2)配置連接工廠:
       <!-- JMS連接工廠 -->
         <bean id="jmsConnectionFactory"class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiTemplate">
         <ref bean="jndiTemplate" />
        </property>
        <property name="jndiName">
         <value>XAConnectionFactory</value>
        </property>
       </bean>
       注意:XAConnectionFactory這個JNDI名字是在%JBOSS_HOME%server\default\deploy\jms文件夾下的jms-ds.xml中定義的(它是由JBoss指定的)。
     (3)配置JmsTemplate組件。在例程中我們使用JmsTemplate102。同時使用defaultDestination屬性來指定JMS目標(biāo)。
      <!-- JMS模板配置 -->
      <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate102">
       <property name="connectionFactory" ref="jmsConnectionFactory" />
       <property name="defaultDestination" ref="destination" />
       <property name="pubSubDomain">
        <value>true</value>
       </property>
       <!-- 等待消息的時間(ms) -->
       <property name="receiveTimeout">
             <value>30000</value>
          </property>
      </bean>
      注意:如果使用topic-subscribe(主題訂閱)模式,該模板的pubSubDomain屬性值為true;若使用PToP(點對點)模式,pubSubDomain屬性值為false或不配置該屬性。
     (4)定義一個JMS目標(biāo)來發(fā)送和接收消息:
      <bean id="destination" class="org.springframework.jndi.JndiObjectFactoryBean">
       <property name="jndiTemplate">
        <ref bean="jndiTemplate" />
       </property>
       <property name="jndiName">
        <value>topic/registerUserTopic</value>
       </property>
      </bean>
     (5)配置發(fā)送者和接收者組件:
      <!-- 消息發(fā)布者 -->
      <bean id="msgProducer" class="com.boco.jms.MessageProducer">
       <property name="jmsTemplate" ref="jmsTemplate" />
      </bean>
      <!-- 消息接收者 -->
      <bean id="msgConsumer" class="com.boco.jms.MessageConsumer">
       <property name="jmsTemplate" ref="jmsTemplate" />
      </bean>
    3.相應(yīng)的類:
     (1). User對象。
       /**
       *  User.java
       *  created on Jul 2, 2006
       *  Copyrights 2006 BOCO,Inc. All rights reserved.
       */
      package com.boco.dto;
      
      import java.io.Serializable;
      
      /**
       * desc: 用戶信息 Bean
       * @author qiujy
       */
      public class User {
       private int id;
       private String username;
       private String password;
       private String email;
       
       public User(){}
       
       //以下為Getter,setter方法略
       ......
      }
      
     (2).消息生產(chǎn)者:
       /**
       *  MessageProducer.java
       *  created on Jul 22, 2006
       *  Copyrights 2006 BOCO,Inc. All rights reserved.
       */
      package com.boco.jms;
      
      import javax.jms.JMSException;
      import javax.jms.MapMessage;
      import javax.jms.Message;
      import javax.jms.Session;
      
      import org.springframework.jms.core.JmsTemplate;
      import org.springframework.jms.core.MessageCreator;
      
      import com.boco.dto.User;
      
      /**
       * desc:消息生產(chǎn)者
       * @author qiujy
       *
       */
      public class MessageProducer {
       /** JMS模板 */
       private JmsTemplate jmsTemplate;
       
       public void setJmsTemplate(JmsTemplate jmsTemplate){
        this.jmsTemplate = jmsTemplate;
       }
       
       public void sendMessage(final User user){
        //調(diào)用模板的send來發(fā)送消息
        jmsTemplate.send(new MessageCreator(){
      
         public Message createMessage(Session session) throws JMSException {
          //構(gòu)造一個要發(fā)送的消息
          MapMessage message = session.createMapMessage();
           message.setInt("id", user.getId());
           message.setString("username", user.getUsername());
           message.setString("password", user.getPassword());
           message.setString("email", user.getEmail());
          System.out.println("send success!!");
          return message;
         }
        });
       }
      }
      
     (3).消息消費者:
      /**
       *  MessageConsumer.java
       *  created on Jul 22, 2006
       *  Copyrights 2006 BOCO,Inc. All rights reserved.
       */
      package com.boco.jms;
      
      import javax.jms.JMSException;
      import javax.jms.MapMessage;
      
      import org.springframework.jms.core.JmsTemplate;
      
      import com.boco.dto.User;
      
      /**
       * desc:消息消費者
       * @author qiujy
       *
       */
      public class MessageConsumer {
       /** JMS模板 */
       private JmsTemplate jmsTemplate;
       
       public void setJmsTemplate(JmsTemplate jmsTemplate){
        this.jmsTemplate = jmsTemplate;
       }
       
       public User receiveMessage(){
        //參數(shù)為Destination的JNDI名字去掉前面的模式類型標(biāo)識
        //MapMessage msg = (MapMessage)jmsTemplate.receive("registerUserQueue");
        MapMessage msg = (MapMessage)jmsTemplate.receive("registerUserTopic");
        User user = new User();
        
        try {
         user.setId(msg.getInt("id"));
         user.setUsername(msg.getString("username"));
         user.setPassword(msg.getString("password"));
         user.setEmail(msg.getString("email"));
        } catch (JMSException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
        }
        
        return user;
       }
      }

     (4).測試用例:
       //======== 生產(chǎn)者測試用例 ===============
       /**
       *  TestMsgProducer.java
       *  created on Jul 22, 2006
       *  Copyrights 2006 BOCO,Inc. All rights reserved.
       */
      package com.boco.jms;
      
      import junit.framework.TestCase;
      
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      import com.boco.dto.User;
      
      /**
       * desc:
       * @author qiujy
       *
       */
      public class TestMsgProducer extends TestCase {
      
       private ApplicationContext context;
       /**
        * @param arg0
        */
       public TestMsgProducer(String arg0) {
        super(arg0);
        context = new ClassPathXmlApplicationContext("applicationContext_jms.xml");
       }
      
       /* (non-Javadoc)
        * @see junit.framework.TestCase#setUp()
        */
       protected void setUp() throws Exception {
        super.setUp();
       }
      
       /* (non-Javadoc)
        * @see junit.framework.TestCase#tearDown()
        */
       protected void tearDown() throws Exception {
        super.tearDown();
       }
      
       /**
        * Test method for {@link com.boco.jms.MessageProducer#sendMessage(com.boco.dto.User)}.
        */
       public void testSendMessage() {
        User user = new User();
        user.setId(132);
        user.setUsername("JMSTest");
        user.setPassword("password");
        user.setEmail("support@boco.com.cn");
        
        MessageProducer producer = (MessageProducer)context.getBean("msgProducer");
        
        producer.sendMessage(user);
        
       }
      
      }

      //============ 消費者測試用例 ===============
      /**
       *  TestMsgConsumer.java
       *  created on Jul 22, 2006
       *  Copyrights 2006 BOCO,Inc. All rights reserved.
       */
      package com.boco.jms;
      
      import junit.framework.TestCase;
      
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      import com.boco.dto.User;
      
      /**
       * desc:
       * @author qiujy
       *
       */
      public class TestMsgConsumer extends TestCase {
       private ApplicationContext context;
       /**
        * @param arg0
        */
       public TestMsgConsumer(String arg0) {
        super(arg0);
        context = new ClassPathXmlApplicationContext("applicationContext_jms.xml");
       }
      
       /* (non-Javadoc)
        * @see junit.framework.TestCase#setUp()
        */
       protected void setUp() throws Exception {
        super.setUp();
       }
      
       /* (non-Javadoc)
        * @see junit.framework.TestCase#tearDown()
        */
       protected void tearDown() throws Exception {
        super.tearDown();
       }
      
       /**
        * Test method for {@link com.boco.jms.MessageConsumer#receiveMessage()}.
        */
       public void testReceiveMessage() {
        MessageConsumer consumer = (MessageConsumer)context.getBean("msgConsumer");
        User user = consumer.receiveMessage();
        assertNotNull(user);
        System.out.println( "id========" + user.getId()
            + "\nname======" + user.getUsername()
            + "\npassword==" + user.getPassword()
            + "\nemail=====" + user.getEmail());
       }
      
      }

    posted on 2011-03-23 14:49 Sheldon Sun 閱讀(269) 評論(0)  編輯  收藏


    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
     
    <2011年3月>
    272812345
    6789101112
    13141516171819
    20212223242526
    272829303112
    3456789

    導(dǎo)航

    統(tǒng)計

    常用鏈接

    留言簿(3)

    隨筆檔案

    文章檔案

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 亚洲色爱图小说专区| 全免费一级毛片在线播放| 国产亚洲精品久久久久秋霞| 老司机午夜免费视频| 亚洲国产午夜中文字幕精品黄网站| 亚洲精品理论电影在线观看| 成人性生交大片免费看无遮挡| 国产.亚洲.欧洲在线| 免费毛片在线看片免费丝瓜视频| ASS亚洲熟妇毛茸茸PICS| 在线观看免费高清视频| 亚洲欧洲AV无码专区| 国产片免费在线观看| 免费在线人人电影网| 久久影视国产亚洲| 久久精品免费视频观看| 亚洲高清免费在线观看| 67194熟妇在线永久免费观看| 亚洲人成电影网站| 国产精品国产午夜免费福利看| 猫咪www免费人成网站| 在线A亚洲老鸭窝天堂| 男人都懂www深夜免费网站| 18gay台湾男同亚洲男同| 69式国产真人免费视频| 亚洲AV无码一区二区乱子仑| 亚洲欧洲久久av| 无码国产精品一区二区免费式芒果| 亚洲成aⅴ人片在线影院八| 日韩精品视频免费在线观看| a高清免费毛片久久| 亚洲黄色免费观看| 国产成人免费a在线资源| 免费无码又爽又刺激一高潮| 亚洲网址在线观看| 四虎1515hm免费国产| 久久国产乱子精品免费女| 亚洲国产高清视频在线观看| 在线观看亚洲免费视频| a级毛片在线免费观看| 99久久国产亚洲综合精品|