Spring 系列,第 4 部分: Spring JMS 訊息處理

xz43發表於2015-10-20

在 Spring 系列 的第 4 期也是最後一期中,我將介紹 Spring JMS(Java 訊息服務)框架的特性。JMS PG 定義了 Java 應用程式通過面向訊息的中介軟體(MOM)建立和交換訊息的標準途徑。

就像在這個系列前面的文章中一樣,我將使用一個簡單的示例來演示 Spring JMS 的特性。您將隨我一道開發一個點對點的(P2P)基於訊息的系統,使用 Spring JMS 框架通過 JMS 介面與 IBM 的 WebSphere MQ 整合。完成練習後,將可以通過這個系統傳送和接收簡單的文字訊息。

在開始之前,請 下載文章的原始碼。請參閱 參考資料 訪問 Spring 框架和 IBM WebSphere MQ 5.3。還需要 Apache Ant 來執行示例應用程式。

Spring JMS

Spring 的 JMS 抽象框架簡化了 JMS API 的使用,並與 JMS 提供者(比如 IBM 的 WebSphere MQ 5.3)平滑地整合。org.springframework.jms.core 包提供了在 Spring 中使用 JMS 的核心功能。它的模板類處理資源的建立和釋放,簡化了 JMS 的使用。

像其他大多數 Spring 模板類一樣,JMS 模板類提供了執行公共操作的 helper 方法。在需要更復雜應用的情況下,類把處理任務的核心委託給使用者實現的回撥介面。JMS 類提供了方便的方法,用來傳送訊息、同步地使用訊息以及向使用者公開 JMS 會話和訊息的製作者。

以下 JMS 包和 org.springframework.jms.core 一起構成了 Spring JMS 的功能:

org.springframework.jms.support 提供轉換 JMSException 的功能。轉換程式碼把檢測到的 JMSException 層次結構轉換成未檢測到異常的映象層次結構。 org.springframework.jms.support.converter 提供 MessageConverter 抽象,以在 Java 物件和 JMS 訊息之間進行轉換。 org.springframework.jms.support.destination 提供管理 JMS 目標的不同策略,比如針對 JNDI 中儲存的目標的服務定位器。 org.springframework.jms.connection 提供適合在獨立應用程式中使用的 ConnectionFactory 實現。connection 還包含針對 JMS 的 Spring PlatformTransactionManager 實現。它允許把 JMS 作為事務性資源整合到 Spring 的事務管理機制中。

IBM WebSphere MQ

就像前面提到的,示例應用程式會用 Spring 的 JMS 框架通過 JMS 介面與 IBM 的 WebSphere MQ 整合。通過在應用程式和 Web 服務之間傳遞訊息,WebSphere MQ 提供了可靠的、有恢復能力的應用程式整合。它使用佇列和事務性工具幫助保持訊息跨網路的完整性。WebSphere MQ 降低了資訊丟失的風險和調和通訊 IT 系統的需要。

WebSphere MQ 在它所支援的所有平臺上提供了一致的應用程式程式設計介面,這有助於讓整合的程式可移植。除了標準介面外,WebSphere MQ 還完整實現了JMS 介面,包括對釋出-訂閱訊息傳遞的支援。WebSphere MQ Explorer 工具可以遠端地管理和配置整個 MQ 網路。管理和配置工具基於開放原始碼的 Eclipse 框架,而且是可擴充套件的。

Spring JMS 模板

Spring 框架提供了 JmsTemplate 的兩個實現。JmsTemplate 類使用 JMS 1.1 API,子類 JmsTemplate102 則使用 JMS 1.0.2 API。我的示例應用程式使用的是 JmsTemplate102。

JMS 模板被用來傳送和接收 JMS 訊息。Spring 採用回撥機制對 JMS 資訊傳遞進行協調。MessageCreator 回撥介面用 JmsTemplate 中的呼叫程式碼提供的 Session 建立訊息。為了支援 JMS API 更復雜的應用,回撥 SessionCallback 向使用者提供了 JMS 會話,而 callback ProducerCallback 則公開了 Session 和 MessageProducer 組合。

清單 1 顯示了示例應用程式使用的 JMS 模板的配置。清單摘自 spring-mqseries-jms.xml 檔案(請參閱 下載)。

清單 1. JMS 模板配置
  <!-- JMS Queue Template -->
  <bean id="jmsQueueTemplate" 
          class="org.springframework.jms.core.JmsTemplate102">
    <property name="connectionFactory">
      <ref bean="jmsQueueConnectionFactory"/>
    </property>
    <property name="destinationResolver">
      <ref bean="jmsDestinationResolver"/>
    </property>
    <property name="pubSubDomain">
      <value>false</value>
    </property>
    <property name="receiveTimeout">
      <value>20000</value>
    </property>
  </bean>

jmsQueueTemplate bean 與 JMS 連線工廠和 JMS 目標解析器繫結在一起,用於解析 JMS 客戶機通過 JNDI 提供的目標佇列名。connectionFactory 屬性指定了如何獲得到 JMS 提供者的連線。在本例中,清單 2 顯示瞭如何從 JNDI 檢索連線工廠。

清單 2. 通過 JNDI 配置 JMS 連線工廠
 <!-- JMS Queue Connection Factory -->
  <bean id="internalJmsQueueConnectionFactory"
          class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiTemplate">
      <ref bean="jndiTemplate"/>
    </property>
    <property name="jndiName">
      <value>MQ_JMS_MANAGER</value>
    </property>
  </bean>

可以看到,JndiObjectFactoryBean 被繫結到 internalJmsQueueConnectionFactory。JndiObjectFactoryBean 用 JndiTemplate 屬性進行 JNDI 查詢。Spring 將用 JndiTemplate 中指定的環境屬性和初始上下文在 JNDI 中查詢連線工廠。清單 3 顯示了 JndiTemplate 配置 bean 的配置。

清單 3. JNDI 查詢的 JNDI 模板配置
<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
    <property name="environment">
      <props>
        <prop key="java.naming.factory.initial">
            com.sun.jndi.fscontext.RefFSContextFactory
        </prop>
        <prop key="java.naming.provider.url">
            file:/C:/JNDI-Directory
        </prop>
      </props>
    </property>
  </bean>

以上配置進行 JNDI 查詢時用 com.sun.jndi.fscontext.RefFSContextFactory 指定初始上下文工廠,用基於檔案的 file:/C:/JNDI-Directory 作為提供者 URL。根據示例應用程式的意圖,JNDI 訪問會採用基於檔案的 FSContext 版本(請參閱 參考資料)的配置把 MQ 佇列繫結到 JNDI。

有了定義好的 JMS 模板,下一步就是把它繫結到示例應用程式中,然後就可以用它傳送和接收訊息了。

Spring JMS 實現

JMS 模板可以繫結到應用程式中,以傳送和接收 JMS 訊息。在清單 4 中可以看出我如何把 清單 1 中的 JMS 模板繫結到示例應用程式中。

清單 4. 把 JmsTemplate 繫結到應用程式中
  <bean id="jmsSender" 
          class="springexample.client.JMSSender">
    <property name="jmsTemplate102">
      <ref bean="jmsQueueTemplate"/>
    </property>
    </bean>
    <bean id="jmsReceiver" 
          class="springexample.client.JMSReceiver">
    <property name="jmsTemplate102">
        <ref bean="jmsQueueTemplate"/>
      </property>
    </bean>

可以看到,我把 jmsQueueTemplate 繫結到用來傳送和接收訊息的 JmsSender 應用程式 bean 和 JmsReceiver bean。清單 5 顯示了與JMSSender 類有關的程式碼。

清單 5. 用 JmsTemplate 傳送 JMS 訊息的 JMSSender
 public class JMSSender {
   private JmsTemplate102 jmsTemplate102;
   public JmsTemplate102 getJmsTemplate102() {
     return jmsTemplate102;
   }
   public void setJmsTemplate102(JmsTemplate102 jmsTemplate102) {
     this.jmsTemplate102 = jmsTemplate102;
   }
   public void sendMesage(){
     jmsTemplate102.send("JMS_RequestResponseQueue", 
                  new MessageCreator() {
        public Message createMessage(Session session) 
                  throws JMSException {
          return session.createTextMessage("This is a sample message");
        }
      });
   }

JMSSender 類用 jmsTemplate102.send() 方法傳送 JMS 訊息。send() 方法的第一個引數是 JNDI 佇列名,佇列名指定了訊息應當傳送到哪裡。(很快就會看到如何把 WebSphere MQ 的佇列名繫結到 JNDI。)send() 方法的第二個引數是 MessageCreator 類。JmsTemplate 中的呼叫程式碼提供了 Session 類,這個類提供了一個建立 JMS 訊息的回撥介面。

下一步是用 JMS 的 Session 類建立一個簡單的文字訊息。在程式碼執行時,訊息會傳遞給 WebSphere MQ 伺服器的佇列。清單 6 顯示了使用JmsTemplate 檢索 JMS 訊息的 JMSReceiver 應用程式 bean 的程式碼。

清單 6. 用 JmsTemplate 檢索 JMS 訊息的 JMSReceiver
  public class JMSReceiver {
    private JmsTemplate102 jmsTemplate102;
    public JmsTemplate102 getJmsTemplate102() {
      return jmsTemplate102;
    }
    public void setJmsTemplate102(JmsTemplate102 jmsTemplate102) {
     this.jmsTemplate102 = jmsTemplate102;
    }
    public void processMessage(){
      Message msg = jmsTemplate102.receive("JMS_RequestResponseQueue");
      try{
        TextMessage textMessage = (TextMessage) msg;
        if( msg!=null){
        System.out.println(" Message Received -->" + 
                    textMessage.getText());
        }
      }catch(Exception e){
            e.printStackTrace();
      }
    }
}

JMSReceiver 類用 jmsTemplate102.receive() 方法同步地接收 JMS 訊息。receive() 方法指定 JNDI 佇列名,並從中檢索訊息。JMSTemplate 類的 processMessage() 方法由接收 JMS 客戶機呼叫。JSMTemplate bean 的屬性 receiveTimeout(列在 JMSTemplate 配置中)指定接收客戶機同步地從佇列中接收訊息時要等候的時間。

現在應用程式的程式碼已完成!下一步就是配置 WebSphere MQ 佇列並把它們繫結到 JNDI 物件。

佇列管理器的設定

在執行應用程式之前,需要設定 WebSphere MQ 的佇列管理器和佇列,並把它們繫結到 JNDI。如果喜歡的話,可以按照這部分的示例做:只需 下載 設定 WebSphere MQ 佇列的批檔案和應用程式的原始碼和部署描述符即可。把 zip 檔案解壓到驅動器 C:。

設定佇列
執行 C:\SpringSeriesPart4JMS\batch 資料夾中的 mqsetup.bat 檔案。這個批檔案要求在 path 環境變數中設定好 MQ 安裝的 bin 資料夾(例如C:\mqseries\bin)。執行了批檔案之後,應當看到訊息 “All valid MQSC commands were processed”。要開啟 MQ Explorer 並檢查已經建立的佇列管理器和佇列,請選擇 Start -> Programs -> IBM MQSeries -> MQSeriesExplorer。圖 1 顯示出示例應用程式QueueManagerMQJMS.QManager 已經建立並正在執行。

圖 1. WebSphere MQ 的 QueueManager 配置 WebSphere MQ 的 QueueManager 配置

請在應用程式螢幕左側皮膚上點選 MQJMS.QManager 下的 Queues 資料夾。應當看到已經建立了一個佇列 RequestResponseQueue,如圖 2 所示。

圖 2. WebSphere MQ 的請求/響應佇列配置 WebSphere MQ 的請求/響應佇列配置

這就完成了佇列的設定。

設定 JMS 和 JNDI 管理

在示例應用程式中,JNDI 的訪問利用了可以從 JNDI 主頁得到的基於檔案的 FSContext 版本(請參閱 參考資料)。FSContext.jar 檔案也包含在 WebSphere MQ 的 JMS 支援當中。請新增資料夾 \MQSeriesInstallable\MQSeries\Java\lib 和 \MQSeriesInstallable\MQSeries\Java\bin 到系統的 PATH 環境變數中。而且,請把 \MQSeriesInstallable\MQSeries\Java\lib 資料夾中的所有 jar 檔案新增到系統的 CLASSPATH 環境變數中。還可以執行 C:\SpringSeriesPart4JMS\batch 資料夾中的 classpath.cmd 檔案,它會設定必要的 path 和 CLASSPATH 變數。要做到這點,只需要修改 classpath.cmd 檔案中的 MQ_JAVA_INSTALL_PATH,把它指到 WebSphere MQ JMS 的安裝目錄。

接下來,修改 \MQSeriesInstallableDirectory\Java\bin 中的 JMSAdmin.config 配置檔案,MQSeries JMS 管理程式用它指明應用程式要使用的上下文工廠和 JNDI 實現的地址。請取消以下行的註釋:

INITIAL_CONTEXT_FACTORY=com.sun.jndi.fscontext.RefFSContextFactory

並註釋掉其餘兩個 INITIAL_CONTEXT_FACTORY 變數。還要取消以下行的註釋:

PROVIDER_URL=file:/C:/JNDI-Directory

並註釋掉其餘兩個 PROVIDER_URL 變數。

可以在 C:\SpringSeriesPart4JMS\batch 資料夾中發現參考的示例配置檔案。

為了儲存 JNDI 物件,請在驅動器 C: 上建立名為 JNDI-Directory 的目錄。切換到 \MQSeriesInstallableDirectory\Java\bin 目錄並執行JMSAdmin 批檔案,應當看到 InitCtx 變數。

逐個輸入以下內容:

def qcf(MQ_JMS_MANAGER) qmgr(MQJMS.QManager)

按回車

def q(JMS_RequestResponseQueue) qmgr(MQJMS.QManager) 
               queue(RequestResponseQueue)

按回車

現在已經把 WebSphere MQ 佇列繫結到 JNDI 物件,作為應用程式客戶可以通過 JNDI 查詢物件。現在剩下的就是看程式碼的實際作用了!

執行示例

要執行示例,請從 spring sourceforge download 下載 Spring 框架和它的所有依賴檔案並解壓,例如解壓到 c:\。會建立資料夾 C:\spring-framework-1.2-rc2(或最新版本)。

要執行 Spring 應用程式,請把本文的原始碼解壓到任意資料夾,例如 c:\。會建立資料夾 SpringSeriesPart4JMS。就像前面提到過的,還需要安裝 Apache Ant 和它的 Spring 依賴 jar 檔案。請把 Spring 庫 —— 即 spring.jar(在 C:\spring-framework-1.2-rc2\dist 中)和 commons-logging.jar(在 C:\spring-framework-1.2-rc2\lib\jakarta-commons 中)拷貝到 SpringSeriesPart4JMS\lib 資料夾。還要把所有的 jar 庫從\MQSeriesInstallableDirectory\Java\lib 目錄拷貝到 SpringSeriesPart4JMS\lib 資料夾。其中包含 MQseries 和 JMS 的相關庫。現在就擁有了構建的依賴集。

接下來,開啟命令提示符,切換到 SpringProject4 目錄,並在命令提示符下輸入以下命令:

> ant -f build-jmssender.xml.

這會構建並執行 SendMQSpringJMS 類,它會呼叫 JMSSender 類,傳送訊息到 WebSphere MQ RequestResponse 佇列。SendMQSpringJMS 還會通過它的 ClassPathXmlApplicationContext 裝入 spring 配置檔案。一旦 bean 全部裝載,就可以通過 Spring 的 ApplicationContext 的getBean() 方法訪問 JMSSender(請參閱清單 7)。

清單 7. 裝入示例應用程式的 Spring 配置
ClassPathXmlApplicationContext appContext = 
                   new ClassPathXmlApplicationContext(new String[] {
     "spring-mqseries-jms.xml"
    });
JMSSender jmsSender = (JMSSender)
        appContext.getBean("jmsSender");

訊息傳遞到佇列上之後,請執行 JMS 接收方客戶機以檢索訊息。請開啟命令提示符,切換到目錄 SpringProject4,並輸入:

> ant -f build-jmsreceiver.xml

這會構建並執行 ReceiveMQSpringJMS 類,該類會呼叫 JMSReceiver 類,以從 WebSphere MQ 的 RequestResponse 佇列接收文字訊息。在控制檯上會列印出以下訊息:

Message Received --> This is a sample message.

結束語

在 Spring 系列的最後這篇文章中,您學習了 Spring JMS 框架的基礎。我首先介紹了示例應用程式的核心元件 —— Spring JMS 框架和 IBM 的 WebSphere MQ 5.3,然後介紹瞭如何用 Spring JMS 模板向 WebSphere MQ 佇列傳送訊息和從中接收訊息。雖然這個示例非常簡單,但是可以把這裡介紹的步驟應用到更復雜的應用程式。

我希望介紹 Spring 框架核心模組的這一系列對您有所幫助。請參閱 參考資料 學習更多有關 Spring 框架和 Spring JMS 的內容。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/9399028/viewspace-1815156/,如需轉載,請註明出處,否則將追究法律責任。

相關文章