?
? ????? PHP ??? ???? ??? ?? ??
JmsTemplate
類有兩個實現(xiàn)方式。JmsTemplate
類使用JMS 1.1的API,
而子類 JmsTemplate102
使用了JMS 1.0.2的API。
使用 JmsTemplate
的代碼只需要實現(xiàn)規(guī)范中定義的回調(diào)接口。
MessageCreator
回調(diào)接口通過JmsTemplate中調(diào)用代碼提供的Session來創(chuàng)建一條消息。
然而,為了允許更復(fù)雜的JMS API應(yīng)用,回調(diào)接口 SessionCallback
為用戶提供JMS session,并且回調(diào)接口 ProducerCallback
將Session和MessageProducer對顯露給用戶。
JMS API有兩種發(fā)送方法,一種采用發(fā)送模式、優(yōu)先級和存活時間作為服務(wù)質(zhì)量(QOS)參數(shù),另一種使用無需QOS參數(shù)的缺省值方法。由于在 JmsTemplate
中有許多種發(fā)送方法,QOS參數(shù)通過bean的屬性方式進行設(shè)置,從而避免在多種發(fā)送方法中重復(fù)。同樣,使用 setReceiveTimeout
屬性值來設(shè)置同步接收調(diào)用的超時值。
某些JMS供應(yīng)者允許通過ConnectionFactory的配置來設(shè)置缺省的QOS值。這樣在調(diào)用 MessageProducer
的發(fā)送方法 send(Destination destination, Message message)
時會使用那些不同的QOS缺省值,而不是JMS規(guī)范中定義的值。所以,為了提供對QOS值的一致管理,JmsTemplate
必須通過設(shè)置布爾值屬性 isExplicitQosEnabled 為true,使它能夠使用自己的QOS值。
JmsTemplate
類的實例 一經(jīng)配置便是線程安全 的。
這很重要,因為這意味著你可以配置一個 JmsTemplate
的單例,然后把這個 共享的 引用安全的注入多個協(xié)作的對象中。
要清楚一點,JmsTemplate
是有狀態(tài)的,因為它維護了 ConnectionFactory
的引用,但這個狀態(tài)時不是會話狀態(tài)。
JmsTemplate
需要一個對 ConnectionFactory
的引用。ConnectionFactory
是JMS規(guī)范的一部分,并且是使用JMS的入口??蛻舳藨?yīng)用通常用它作工廠配合JMS提供者去創(chuàng)建連接,并封裝許多和供應(yīng)商相關(guān)的配置參數(shù),例如SSL的配置選項。
當在EJB里使用JMS時,供應(yīng)商會提供JMS接口的實現(xiàn),這樣們可以參與聲明式事務(wù)管理并提供連接池和會話池。
為了使用這個JMS實現(xiàn),Java EE容器通常要求你在EJB或servlet部署描述符中聲明一個JMS連接工廠做為 resource-ref。
為確??梢栽贓JB內(nèi)使用 JmsTemplate
的這些特性,客戶應(yīng)用應(yīng)當確保它引用了被管理的ConnectionFactory實現(xiàn)。
Spring提供了一個 ConnectionFactory
接口的實現(xiàn),SingleConnectionFactory
,它將在所有的 createConnection
調(diào)用中返回一個相同的 Connection
,并忽略所有對 close
的調(diào)用。這在測試和獨立環(huán)境中相當有用,因為多個 JmsTemplate
調(diào)用可以使用同一個連接以跨越多個事務(wù)。SingleConnectionFactory
通常引用一個來自JNDI的標準 ConnectionFactory
。
和連接工廠一樣,目的地是可以在JNDI中存儲和獲取的JMS管理的對象。配置一個Spring應(yīng)用上下文時,可以使用JNDI工廠類 JndiObjectFactoryBean
把對你對象的引用依賴注入到JMS目的地中。然而,如果在應(yīng)用中有大量的目的地,或者JMS供應(yīng)商提供了特有的高級目的地管理特性,這個策略常常顯得很麻煩。創(chuàng)建動態(tài)目的地或支持目的地的命名空間層次就是這種高級目的地管理的例子。JmsTemplate
將目的地名稱到JMS目的地對象的解析委派給 DestinationResolver
接口的一個實現(xiàn)。JndiDestinationResolver
是 JmsTemplate
使用的默認實現(xiàn),并且提供動態(tài)目的地解析。同時 JndiDestinationResolver
作為JNDI中的目的地服務(wù)定位器,還可選擇回退去使用 DynamicDestinationResolver
中的行為。
經(jīng)常見到一個JMS應(yīng)用中使用的目的地在運行時才知道,因此,當部署一個應(yīng)用時,它不能用可管理的方式創(chuàng)建。這是經(jīng)常發(fā)生的,因為在互相作用的系統(tǒng)組件間有些共享應(yīng)用邏輯會在運行的時候按照共同的命名規(guī)范創(chuàng)建消息目的地。雖然動態(tài)創(chuàng)建目的地不是JMS規(guī)范的一部分,但是大多數(shù)供應(yīng)商已經(jīng)提供了這個功能。
用戶為動態(tài)創(chuàng)建的目的地定義和臨時目的地不同的名字,并且通常不被注冊到JNDI中。不同供應(yīng)商創(chuàng)建動態(tài)消息目的地所使用的API差異很大,因為和目的地相關(guān)的屬性是供應(yīng)商特有的。然而,有時由供應(yīng)商會作出一個簡單的實現(xiàn)選擇-忽略JMS規(guī)范中的警告,使用 TopicSession
的方法 createTopic(String topicName)
或者 QueueSession
的方法 createQueue(String queueName)
來創(chuàng)建一個帶默認值屬性的新目的地。依賴于供應(yīng)商的實現(xiàn),DynamicDestinationResolver
也可能創(chuàng)建一個物理上的目的地,而不再僅僅是一個解析。
布爾屬性 pubSubDomain 用來配置 JmsTemplate
使用什么樣的JMS域。這個屬性的默認值是false,使用點到點的域,也就是隊列。在1.0.2的實現(xiàn)中,這個屬性值用來決定 JmsTemplate
將消息發(fā)送到一個 Queue
還是一個 Topic
。這個標志在1.1的實現(xiàn)中對發(fā)送操作沒有影響。然而,在這兩個JMS版本中,這個屬性決定了通過接口 DestinationResolver
的實現(xiàn)來決定如何解析動態(tài)消息目的地。
你還可以通過屬性 defaultDestination 配置一個帶有默認目的地的 JmsTemplate
。不指明目的地的發(fā)送和接受操作將使用該默認目的地。
在EJB世界里,JMS消息最常用的功能之一是用于實現(xiàn)消息驅(qū)動Bean(MDB)。Spring提供了一個方法來創(chuàng)建消息驅(qū)動的POJO(MDP),并且不會把用戶綁定在某個EJB容器上。(關(guān)于Spring的MDP支持的細節(jié)請參考標題為 第?19.4.2?節(jié) “異步接收 - 消息驅(qū)動的POJO” 的章節(jié)。)
通常用消息監(jiān)聽器容器從JMS消息隊列接收消息并驅(qū)動被注射進來的MDP。消息監(jiān)聽器容器負責消息接收的多線程處理并分發(fā)到各MDP中。一個消息偵聽容器是MDP和消息提供者之間的一個中介,用來處理消息接收的注冊,事務(wù)管理的參與,資源獲取和釋放,異常轉(zhuǎn)換等等。這使得應(yīng)用開發(fā)人員可以專注于開發(fā)和接收消息(可能的響應(yīng))相關(guān)的(復(fù)雜)業(yè)務(wù)邏輯,把和JMS基礎(chǔ)框架有關(guān)的樣板化的部分委托給框架處理。
Spring提供了三種 AbstractMessageListenerContainer
的子類,每種各有其特點。
這個消息偵聽容器是三種中最簡單的。它在啟動時創(chuàng)建固定數(shù)量的JMS session并在容器的整個生命周期中使用它們。這個類不能動態(tài)的適應(yīng)運行時的要求或參與消息接收的事務(wù)處理。然而它對JMS提供者的要求也最低。它只需要簡單的JMS API。
這個消息偵聽器使用的最多。和 SimpleMessageListenerContainer
相反,這個子類可以動態(tài)適應(yīng)運行時侯的要求,也可以參與事務(wù)管理。每個收到的消息都注冊到一個XA事務(wù)中(如果使用 JtaTransactionManager
配置過),這樣就可以利用XA事務(wù)語義的優(yōu)勢了。這個類在對JMS提供者的低要求和提供包括事務(wù)參于等的強大功能上取得了很好的平衡。
Spring提供了 JmsTransactionManager
為單個JMS ConnectionFactory
管理事務(wù)。這將允許JMS應(yīng)用利用 第?9?章 事務(wù)管理
中描述的Spring的事務(wù)管理功能。JmsTransactionManager
綁定 ConnectionFactory
的一個Connection/Session對到線程上,來提供本地資源事務(wù)。JmsTemplate
自動檢測到這些事務(wù)性資源從而對它們進行操作。
在Java EE環(huán)境中,SingleConnectionFactory
將把Connection和Session放到緩沖池中,因此這些資源在事務(wù)中得到了有效的復(fù)用。在獨立環(huán)境中使用Spring的 SingleConnectionFactory
會存在共享的JMS Connection
,但每個事務(wù)有自己獨立的 Session
。另外可以考慮使用供應(yīng)商特定的池適配器,,如ActiveMQ的 PooledConnectionFactory
類。
JmsTemplate
也可以和 JtaTransactionManager
以及具有XA能力的JMS ConnectionFactory
一起使用來提供分布式事務(wù)。記住這需要使用JTA事務(wù)管理器或合適的可配置的XA ConnectionFactory!(參考你所使用的J2EE服務(wù)器/JMS供應(yīng)商的文檔。)
當使用JMS API從一個 Connection
中創(chuàng)建 Session
時,在受管理的和非受管理的事務(wù)環(huán)境下重用代碼會可能會讓人迷惑。這是因為JMS API只有一個工廠方法來創(chuàng)建 Session
,并且它需要用于事務(wù)和模式確認的值。在受管理的環(huán)境下,由事務(wù)結(jié)構(gòu)環(huán)境負責設(shè)置這些值,這樣在供應(yīng)商包裝的JMS連接中可以忽略這些值。當在一個非管理性的環(huán)境中使用 JmsTemplate
時,你可以通過使用屬性 SessionTransacted
和 SessionAcknowledgeMode
來指定這些值。當 JmsTemplate
配合 PlatformTransactionManager
使用時,模板將一直被賦予一個事務(wù)性JMS的 Session
。