javascript
java 配置jmstemplate_Spring JMSTemplate 与 JMS 原生API比较
JMSUtil與Spring JmsTemplate的對比
Author:信仰
Date:2012-4-20
未完待續(xù),截止日期2012-4-20
從以下幾方面比較JMSUtil和Spring JmsTemplate
l??對JNDI的支持
l??對ConnectionFactory、Connection、Destination、Session、MessageProducer、MessageConsumer對象的處理
l??對事務(wù)的處理
l??不同類型的消息處理
l??異常處理
Spring
JMSUtil
對JNDI的支持
支持,可配置,可編碼
支持,只能編碼
對ConnectionFactory、
Connection、
Destination、
Session、
MessageProducer、
MessageConsumer對象的處理
配置
編碼
對事務(wù)的處理
配置
編碼
對不同類型消息處理
自動轉(zhuǎn)換
編碼轉(zhuǎn)換
異常處理
運(yùn)行時(shí)異常,無需寫try…catch
檢查異常,必須寫try…catch
1.???對JNDI的支持
兩者都支持JNDI和非JNDI方式。兩者的JNDI名稱都是在XML中配置完成的,這一點(diǎn)上兩者不存在誰更有優(yōu)勢。
1.1.?Spring對JNDI的支持
1.1.1.????Spring JMS?實(shí)現(xiàn)
JNDI查詢的JNDI模板配置
com.ibm.websphere.naming.WsnInitialContextFactory
iiop://127.0.0.1:2813/
通過JNDI配置JMS連接工廠
class="org.springframework.jndi.JndiObjectFactoryBean">
MQ_JMS_MANAGER
JMS模板配置
false
20000
把JmsTemplate綁定到應(yīng)用程序中
用JmsTemplate發(fā)送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");
}
});
}
}
用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();
}
}
}
1.2.?JMSUtil對JNDI的支持
1.2.1.????JMSUtil的實(shí)現(xiàn)
XML配置:
${jms.logQueueConFactory}
${jms.errLogQueueName}
0
1
JMSUtil中發(fā)送消息報(bào)文和對象報(bào)文的方法:
public?static?void?putTextMessage(MsgData?msgData,?boolean?transacted)?throwsMessageException
{
……
ConnectionFactory connectionFactory =?null;
Connection connection =?null;
Session session =?null;
Destination destination =?null;
MessageProducer messageProducer =?null;
try
{
connectionFactory = (ConnectionFactory)
LocalContext.lookup(msgData.getQcfName(),?true);
destination = (Destination) LocalContext.lookup(msgData.getOutputQ,?false);
connection = connectionFactory.createConnection();
session = connection.createSession(transacted, Session.AUTO_ACKNOWLEDGE);
messageProducer = session.createProducer(destination);
//?修改為 二進(jìn)制 ,字符集為可配置項(xiàng),缺省為?GBK
BytesMessage message = session.createBytesMessage();
if?(msgData.getExpirationTime() !=?null)
{
messageProducer
.setTimeToLive(msgData.getExpirationTime().longValue());
}
……
message
.writeBytes(msgData.getMsg()
.getBytes(MtoFactory.getInstance().getCharsetName()));
}
catch?( JMSException e1 )
{
String errorMsg = "發(fā)送消息失敗:錯(cuò)誤碼" + e1.getErrorCode() + ",錯(cuò)誤原因:" + e1.getMessage();
……
}
catch?(NamingException e1)
{
String errorMsg =?"發(fā)送消息失敗,查找對應(yīng)的資源未找到,錯(cuò)誤原因:"?+ e1.getMessage();
……
}
catch?( UnsupportedEncodingException ue )
{
String errorMsg =?"發(fā)送消息失敗,不支持的字符集: "?+ MtoFactory.getInstance().getCharsetName();
log.error(errorMsg, ue);
throw?new?MessageException(errorMsg, ue);
}
catch?(RuntimeException e)
{
String errorMsg =?"發(fā)送消息失敗:"?+ e.getMessage();
……
}
finally
{
if?( connection !=?null)
{
if( messageProducer !=?null)
{
try
{
messageProducer.close();
}
catch?( JMSException e2 )
{
log.error("關(guān)閉messageProducer異常", e2);
}
}
if( session !=?null)
{
try
{
session.close();
}
catch?( JMSException e2 )
{
log.error("關(guān)閉session異常", e2);
}
}
try
{
connection.close();
}
catch?( JMSException e2 )
{
log.error("關(guān)閉connection異常", e2);
}
}
}
}
/**
*?發(fā)送一條對象報(bào)文,將一個(gè)對象放入隊(duì)列中
*
*?@param?qcfName
*????????????連接工廠名
*?@param?outputQ
*????????????隊(duì)列名
*?@param?obj
*????????????要發(fā)送的對象
*?@param?transacted?是否參與事務(wù)
*?@throws?MessageException
*/
public?static?void?putObjectMessage(String qcfName, String outputQ, Serializable obj,boolean?transacted)?throws?MessageException
{
ConnectionFactory connectionFactory =?null;
Connection connection =?null;
Session session =?null;
Destination destination =?null;
MessageProducer messageProducer =?null;
try
{
connectionFactory = (ConnectionFactory) LocalContext.lookup(qcfName,?true);
destination = (Destination) LocalContext.lookup(outputQ,?false);
connection = connectionFactory.createConnection();
session = connection.createSession(transacted, Session.AUTO_ACKNOWLEDGE);
messageProducer = session.createProducer(destination);
ObjectMessage objmsg = session.createObjectMessage(obj);
objmsg.setJMSType("transfer");
messageProducer.send(objmsg);
}
catch?( JMSException e1 )
{
String errorMsg = "發(fā)送消息失敗:錯(cuò)誤碼" + e1.getErrorCode() + ",錯(cuò)誤原因:" + e1.getMessage();
……
}
catch?(NamingException e1)
{
String errorMsg =?"發(fā)送消息失敗,查找對應(yīng)的資源未找到,錯(cuò)誤原因:"?+ e1.getMessage();
……
}
catch?( UnsupportedEncodingException ue )
{
String errorMsg =?"發(fā)送消息失敗,不支持的字符集: "?+ MtoFactory.getInstance().getCharsetName();
log.error(errorMsg, ue);
throw?new?MessageException(errorMsg, ue);
}
catch?(RuntimeException e)
{
String errorMsg =?"發(fā)送消息失敗:"?+ e.getMessage();
……
}
finally
{
if?( connection !=?null)
{
if( messageProducer !=?null)
{
try
{
messageProducer.close();
}
catch?( JMSException e2 )
{
log.error("關(guān)閉messageProducer異常", e2);
}
}
if( session !=?null)
{
try
{
session.close();
}
catch?( JMSException e2 )
{
log.error("關(guān)閉session異常", e2);
}
}
try
{
connection.close();
}
catch?( JMSException e2 )
{
log.error("關(guān)閉connection異常", e2);
}
}
}
}
2.??對ConnectionFactory、Connection、Destination、Session、MessageProducer、MessageConsumer的處理
Spring對打開和關(guān)閉連接的處理由容器控制,而JMS打開和關(guān)閉連接的處理由應(yīng)用來控制。
2.1.?JMSUtil對上述對象的處理
關(guān)閉上述對象:
finally
{
if?( connection !=?null)
{
if( messageProducer !=?null)
{
try
{
messageProducer.close();
}
catch?( JMSException e2 )
{
log.error("關(guān)閉messageProducer異常", e2);
}
}
if( session !=?null)
{
try
{
session.close();
}
catch?( JMSException e2 )
{
log.error("關(guān)閉session異常", e2);
}
}
try
{
connection.close();
}
catch?( JMSException e2 )
{
log.error("關(guān)閉connection異常", e2);
}
}
}
3.???對事務(wù)的處理
3.1.?Spring JMSTemplate對事物的處理方式
3.1.1.????本地事務(wù)
Spring為JMS提供了本地事務(wù)管理的能力,JMS事務(wù)管理器和數(shù)據(jù)庫事務(wù)管理器都是PlatformTransactionManager接口的實(shí)現(xiàn)類,Spring的org.springframework.jms.connection包提供了用于管理JMS本地事務(wù)JmsTransactionManager事務(wù)管理器,JMS1.0.2則對應(yīng)JmsTransactionManager102。
class=”org.springframework.jms.connection.JmsTransactionManager”>
在進(jìn)行標(biāo)準(zhǔn)的Spring事務(wù)配置后,就能夠管理那些基于JmsTemplate編寫的JMS處理類。對于那些未基于JmsTemplate編寫的JMS處理類,可以讓消息監(jiān)聽器容器對它們進(jìn)行事務(wù)管理。DefaultMessageListenerContainer和ServerSessionMessageListenerContainer都支持通過消息監(jiān)聽器使用JMS事務(wù),不過必須為他們提供一個(gè)事務(wù)管理器,如下配置:
class=”org.springframework.jms.connection.JmsTransactionManager”>
class=”org.springframeword.jms.listener.DefaultMessageListenerContainer”>
3.1.2.????JTA事務(wù)
啟用JTA事務(wù)后,用戶可以讓數(shù)據(jù)庫操作、JMS操作以及其它符合JTA標(biāo)準(zhǔn)的操作工作在同一個(gè)全局事務(wù)中。
對于JMS來說,用戶必須從Java EE的JNDI中獲取XA支持的JMS ConnectionFactory。
對于Spring配置來說,JTA全局事務(wù)和本地事務(wù)的差別并不大,用戶只需要聲明一個(gè)JtaTransactionManager事務(wù)管理器,將事務(wù)委托給Java EE應(yīng)用服務(wù)器就可以了。當(dāng)然,ConnectionFactory必須使用XA支持的JMSConnectionFactory。
下面是讓一個(gè)數(shù)據(jù)源和一個(gè)JMSConnectionFactory工作于同一個(gè)JTA事務(wù)的具體配置:
class=”org.springframework.transaction.jta.JtaTransactionManager”/>
3.2.?JMSUtil對事物的處理方式
3.2.1.????本地事務(wù)
在Session可以控制交易,首選Session要定義成transacted,然后通過調(diào)用commit或rollback來提交或者回滾事務(wù)。
QueueSession queueSession
= connection.createQueueSession(boolean transacted, int acknowledgeMode);
TopicSession topicSession
= connection.createTopicSession(Boolean transacted, int acknowledgeMode);
Session.commit();
Session.rollback()
注意:如果transacted = true,則acknowledgeMode的值便無關(guān)緊要。
3.2.2.????JTA事務(wù)
還不太了解……
4.???不同類型的消息的處理
JMS有多鐘類型的消息:
l??javax.jms.TextMessage
l??javax.jms.MapMessage
l??javax.jms.ObjectMessage
l??javax.jms.BytesMessage
4.1.?Spring使用消息轉(zhuǎn)換器發(fā)送/接收消息
Spring將POJO和JMS消息的雙向轉(zhuǎn)換工作抽象到MessageConverter中,在JmsTemplate中提供了幾個(gè)convertAndSend()和receiveAndConvert()方法,這些方法自動使用MessageConverter完成消息的轉(zhuǎn)換工作。
4.1.1.????消息轉(zhuǎn)換器
在org.springframework.jms.support.converter包中,Spring提供了消息轉(zhuǎn)換器的支持,首先看一下MessageConverter接口的兩個(gè)方法:
l??Object fromMessage(Message message)
l??Message toMessage(Object object, Session session)
MessageConverter接口的目的是為了向調(diào)用者屏蔽JMS細(xì)節(jié),在JMS之上搭建的一個(gè)隔離層,這樣調(diào)用者可以直接發(fā)送和接收POJO,而不是發(fā)送和接收J(rèn)MS相關(guān)消息,調(diào)用者的程序?qū)⒌玫竭M(jìn)一步簡化。
JMS消息類型
POJO類型
javax.jms.TextMessage
String
javax.jms.MapMessage
java.util.Map
javax.jms.ObjectMessage
java.io.Serializable
javax.jms.BytesMessage
byte[] bytes
當(dāng)轉(zhuǎn)換發(fā)生錯(cuò)誤時(shí),Spring將拋出MessageConversionException異常,該異常是org.springframework.jms.JmsException的子類。
JmsTemplate和JmsTemplate102分別使用SimpleMessageConverter和SimpleMessageConverter102作為默認(rèn)的消息轉(zhuǎn)換器。用戶也可以通過實(shí)現(xiàn)MessageConverter定義自己的消息轉(zhuǎn)換器,并在配置JmsTemplate時(shí)通過messageConverter屬性指定自己的消息轉(zhuǎn)換器。
4.1.2.????發(fā)送POJO消息
4.1.2.1.???????將POJO簡單地映射為Message對象發(fā)送
假設(shè)User是一個(gè)POJO,其結(jié)構(gòu)如下:
package com.baobaotao.domain;
……
public class User?implement Serializable
{
private String username;
private String userId;
private String email;
private int level;
//?省略get/setter
}
這個(gè)POJO必須實(shí)現(xiàn)Serializable接口,以便可以將對象序列化后作為消息發(fā)送,除此以外沒有任何其他的要求。
將User作為JMS消息發(fā)送的操作僅需要一行簡單的代碼就可以完成:
package com.baobaotao.jms;
……
import com.baobaotao.domain.User;
public class MessageSender extends JmsGatewaySupport
{
……
public void sendUserMsg(User user)
{
//發(fā)送User對象
super.getJmsTemplate.convertAndSend(“userMsgQ”, user);
}
}
JmsTemplate提供了幾個(gè)重載版本的convertAndSend()方法:
l??convertAndSend
public void convertAndSend(Object?message)
Send the given object to the default destination, converting the object to a JMS message with a configured MessageConverter.
This will only work with a default destination specified!
Specified by:
Parameters:
message?- the object to convert to a message
Throws:
JmsException?- converted checked JMSException to unchecked
l??convertAndSend
public void convertAndSend(Destination?destination,
Object?message)
Send the given object to the specified destination, converting the object to a JMS message with a configured MessageConverter.
Specified by:
Parameters:
destination?- the destination to send this message to
message?- the object to convert to a message
Throws:
JmsException?- converted checked JMSException to unchecked
l??convertAndSend
public void convertAndSend(String?destinationName,
Object?message)
Send the given object to the specified destination, converting the object to a JMS message with a configured MessageConverter.
Specified by:
Parameters:
destinationName?- the name of the destination to send this message to (to be resolved to an actual destination by a DestinationResolver)
message?- the object to convert to a message
Throws:
JmsException?- checked JMSException converted to unchecked
l??convertAndSend
public void convertAndSend(Object?message,
Send the given object to the default destination, converting the object to a JMS message with a configured MessageConverter. The MessagePostProcessor callback allows for modification of the message after conversion.
This will only work with a default destination specified!
Specified by:
Parameters:
message?- the object to convert to a message
postProcessor?- the callback to modify the message
Throws:
JmsException?- checked JMSException converted to unchecked
l??convertAndSend
public void convertAndSend(Destination?destination,
Object?message,
Send the given object to the specified destination, converting the object to a JMS message with a configured MessageConverter. The MessagePostProcessor callback allows for modification of the message after conversion.
Specified by:
Parameters:
destination?- the destination to send this message to
message?- the object to convert to a message
postProcessor?- the callback to modify the message
Throws:
JmsException?- checked JMSException converted to unchecked
l??convertAndSend
public void convertAndSend(String?destinationName,
Object?message,
Send the given object to the specified destination, converting the object to a JMS message with a configured MessageConverter. The MessagePostProcessor callback allows for modification of the message after conversion.
Specified by:
Parameters:
destinationName?- the name of the destination to send this message to (to be resolved to an actual destination by a DestinationResolver)
message?- the object to convert to a message.
postProcessor?- the callback to modify the message
Throws:
JmsException?- checked JMSException converted to unchecked
4.1.2.2.???????將POJO映射為Message后進(jìn)行后置處理
通過以上方法發(fā)送POJO,JmsTemplate僅會按照簡單的映射方式發(fā)送JMS消息,如果我們需要在此基礎(chǔ)上進(jìn)一步設(shè)置Message的Header和Properties部分的值,一種方法是編寫自己的消息轉(zhuǎn)換器達(dá)到目的,還有一種更好的方法是使用Spring的org.springframework.jms.core.MessagePostProcessor回調(diào)接口。JmsTemplate在使用MessageConverter將POJO轉(zhuǎn)換為JMS消息后以及發(fā)送消息前,將調(diào)用MessagePostProcessor對JMS消息進(jìn)行后置加工處理。因此,我們有機(jī)會通過一個(gè)自定義的MessagePostProcessor回調(diào)接口對JMS消息對象進(jìn)行“修正性”工作。
下面,我們在User轉(zhuǎn)換為ObjectMessage后,為消息對象指定過期時(shí)間并設(shè)置一個(gè)屬性:
package com.baobaotao.jms;
……
import org.springframework。jms.core.MessagePostProcessor;
public class MessageSender extends JmsGatewaySupport
{
public void sendUserMsg2(final User user)
{
getJmsTemplate().convertAndSend(“userMsgQ”,
user,
new MessagePostProcessor()
{
public Message postProcessMessage(Message message) throws JMSException
{
message.setJMSExpiration(System.currentTimeMillis() + 60 * 60 * 1000); //設(shè)置過期時(shí)間:一小時(shí)后過期
message.setIntProperty(“l(fā)evel”, user.getLevel()); //?設(shè)置一個(gè)屬性
}
});
}
}
4.1.3.????接收POJO消息
4.2.?JMSUtil必須直接實(shí)例化不同類型的消息對象
4.2.1.????發(fā)送消息
例如,如果要發(fā)送的消息是javax.jms.TextMessage類型,代碼如下所示:
TextMessage txtMsg = queueSession.createTextMessage(obj);
messageProducer.send(txtMsg);
4.2.2.????接收消息
例如,如果要接收的消息是javax.jms.TextMessage類型,代碼如下所示:
Message m = messageConsumer.receive(1000 * 1);
if ( m instanceof TextMessage )
{
TextMessage textMessage = (TextMessage) m;
System.out.println(textMessage.getText());
}
5.???異常處理
5.1.?Spring JmsTemplate?運(yùn)行時(shí)異常
JMS的異常都是檢查型異常,使用原生JMS API,用戶需要提供繁瑣的異常捕獲代碼。而Spring將檢查型異常轉(zhuǎn)化為運(yùn)行期異常。
Spring在org.springframework.jms包為javax.jms包中所有的異常類提供了類型轉(zhuǎn)換的鏡像實(shí)現(xiàn)。如:org.springframework.jms.IllegalStateException對應(yīng)javax.jms.IllegalStateExceptipn;org.springframework.jms.InvalidClientIDException對應(yīng)javax.jms.InvalidClientIDException等。Spring中所有JMS相關(guān)的異常都繼承于JmsException類。
此外,Spring還提供了一些特定的JMS異常類:
l??DestinationResolutionException:Spring允許通過簡單的字符串指定消息地址,DestinationResolver在解析消息地址發(fā)生錯(cuò)誤時(shí)拋出異常;
l??SynchedLocalTransactionFailedException:如果在同步本地事務(wù)發(fā)生異常時(shí)拋出該異常,由于事務(wù)已經(jīng)結(jié)束后,再次嘗試同步事務(wù)時(shí)會發(fā)生這個(gè)異常;
l??UncategorizedJmsException:任何未被歸類的其他類型一場。
5.2.?JMSUtil檢查異常
總結(jié)
以上是生活随笔為你收集整理的java 配置jmstemplate_Spring JMSTemplate 与 JMS 原生API比较的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python不支持的数据类型有achar
- 下一篇: c#网页自动化脚本语言,c# – 创建用