在 Spring 系列 的第 4 期也是最後一期中,我將介紹 Spring JMS(Java 消息服務)框架的特性。JMS PG 定義了 Java 應用程序經過面向消息的中間件(MOM)建立和交換消息的標準途徑。java
就像在這個系列前面的文章中同樣,我將使用一個簡單的示例來演示 Spring JMS 的特性。您將隨我一道開發一個點對點的(P2P)基於消息的系統,使用 Spring JMS 框架經過 JMS 接口與 IBM 的 WebSphere MQ 集成。完成練習後,將能夠經過這個系統發送和接收簡單的文本消息。web
在開始以前,請 下載文章的源代碼。請參閱 參考資料 訪問 Spring 框架和 IBM WebSphere MQ 5.3。還須要 Apache Ant 來運行示例應用程序。spring
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.supportsession
提供轉換 JMSException
的功能。轉換代碼把檢測到的 JMSException
層次結構轉換成未檢測到異常的鏡像層次結構。app
org.springframework.jms.support.converter框架
提供 MessageConverter
抽象,以在 Java 對象和 JMS 消息之間進行轉換。jsp
org.springframework.jms.support.destination
提供管理 JMS 目標的不一樣策略,好比針對 JNDI 中保存的目標的服務定位器。
org.springframework.jms.connection
提供適合在獨立應用程序中使用的 ConnectionFactory
實現。connection 還包含針對 JMS 的 Spring PlatformTransactionManager
實現。它容許把 JMS 做爲事務性資源集成到 Spring 的事務管理機制中。
就像前面提到的,示例應用程序會用 Spring 的 JMS 框架經過 JMS 接口與 IBM 的 WebSphere MQ 集成。經過在應用程序和 Web 服務之間傳遞消息,WebSphere MQ 提供了可靠的、有恢復能力的應用程序集成。它使用隊列和事務性工具幫助保持消息跨網絡的完整性。WebSphere MQ 下降了信息丟失的風險和調和通訊 IT 系統的須要。
WebSphere MQ 在它所支持的全部平臺上提供了一致的應用程序編程接口,這有助於讓集成的程序可移植。除了標準接口外,WebSphere MQ 還完整實現了JMS 接口,包括對發佈-訂閱消息傳遞的支持。WebSphere MQ Explorer 工具能夠遠程地管理和配置整個 MQ 網絡。管理和配置工具基於開放源碼的 Eclipse 框架,並且是可擴展的。
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 文件(請參閱 下載)。
<!-- 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 檢索鏈接工廠。
<!-- 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 的配置。
<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 模板,下一步就是把它綁定到示例應用程序中,而後就能夠用它發送和接收消息了。
JMS 模板能夠綁定到應用程序中,以發送和接收 JMS 消息。在清單 4 中能夠看出我如何把 清單 1 中的 JMS 模板綁定到示例應用程序中。
<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
類有關的代碼。
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 的代碼。
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 顯示出示例應用程序QueueManager
MQJMS.QManager
已經建立並正在運行。
請在應用程序屏幕左側面板上點擊 MQJMS.QManager
下的 Queues 文件夾。應當看到已經建立了一個隊列 RequestResponseQueue
,如圖 2 所示。
這就完成了隊列的設置。
設置 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)。
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 的內容。