javascript
java 配置jmstemplate_Spring JMSTemplate 与 JMS 原生API比较
JMSUtil與Spring JmsTemplate的對比
Author:信仰
Date:2012-4-20
未完待續,截止日期2012-4-20
從以下幾方面比較JMSUtil和Spring JmsTemplate
l??對JNDI的支持
l??對ConnectionFactory、Connection、Destination、Session、MessageProducer、MessageConsumer對象的處理
l??對事務的處理
l??不同類型的消息處理
l??異常處理
Spring
JMSUtil
對JNDI的支持
支持,可配置,可編碼
支持,只能編碼
對ConnectionFactory、
Connection、
Destination、
Session、
MessageProducer、
MessageConsumer對象的處理
配置
編碼
對事務的處理
配置
編碼
對不同類型消息處理
自動轉換
編碼轉換
異常處理
運行時異常,無需寫try…catch
檢查異常,必須寫try…catch
1.???對JNDI的支持
兩者都支持JNDI和非JNDI方式。兩者的JNDI名稱都是在XML中配置完成的,這一點上兩者不存在誰更有優勢。
1.1.?Spring對JNDI的支持
1.1.1.????Spring JMS?實現
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綁定到應用程序中
用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");
}
});
}
}
用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的實現
XML配置:
${jms.logQueueConFactory}
${jms.errLogQueueName}
0
1
JMSUtil中發送消息報文和對象報文的方法:
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);
//?修改為 二進制 ,字符集為可配置項,缺省為?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 = "發送消息失敗:錯誤碼" + e1.getErrorCode() + ",錯誤原因:" + e1.getMessage();
……
}
catch?(NamingException e1)
{
String errorMsg =?"發送消息失敗,查找對應的資源未找到,錯誤原因:"?+ e1.getMessage();
……
}
catch?( UnsupportedEncodingException ue )
{
String errorMsg =?"發送消息失敗,不支持的字符集: "?+ MtoFactory.getInstance().getCharsetName();
log.error(errorMsg, ue);
throw?new?MessageException(errorMsg, ue);
}
catch?(RuntimeException e)
{
String errorMsg =?"發送消息失敗:"?+ e.getMessage();
……
}
finally
{
if?( connection !=?null)
{
if( messageProducer !=?null)
{
try
{
messageProducer.close();
}
catch?( JMSException e2 )
{
log.error("關閉messageProducer異常", e2);
}
}
if( session !=?null)
{
try
{
session.close();
}
catch?( JMSException e2 )
{
log.error("關閉session異常", e2);
}
}
try
{
connection.close();
}
catch?( JMSException e2 )
{
log.error("關閉connection異常", e2);
}
}
}
}
/**
*?發送一條對象報文,將一個對象放入隊列中
*
*?@param?qcfName
*????????????連接工廠名
*?@param?outputQ
*????????????隊列名
*?@param?obj
*????????????要發送的對象
*?@param?transacted?是否參與事務
*?@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 = "發送消息失敗:錯誤碼" + e1.getErrorCode() + ",錯誤原因:" + e1.getMessage();
……
}
catch?(NamingException e1)
{
String errorMsg =?"發送消息失敗,查找對應的資源未找到,錯誤原因:"?+ e1.getMessage();
……
}
catch?( UnsupportedEncodingException ue )
{
String errorMsg =?"發送消息失敗,不支持的字符集: "?+ MtoFactory.getInstance().getCharsetName();
log.error(errorMsg, ue);
throw?new?MessageException(errorMsg, ue);
}
catch?(RuntimeException e)
{
String errorMsg =?"發送消息失敗:"?+ e.getMessage();
……
}
finally
{
if?( connection !=?null)
{
if( messageProducer !=?null)
{
try
{
messageProducer.close();
}
catch?( JMSException e2 )
{
log.error("關閉messageProducer異常", e2);
}
}
if( session !=?null)
{
try
{
session.close();
}
catch?( JMSException e2 )
{
log.error("關閉session異常", e2);
}
}
try
{
connection.close();
}
catch?( JMSException e2 )
{
log.error("關閉connection異常", e2);
}
}
}
}
2.??對ConnectionFactory、Connection、Destination、Session、MessageProducer、MessageConsumer的處理
Spring對打開和關閉連接的處理由容器控制,而JMS打開和關閉連接的處理由應用來控制。
2.1.?JMSUtil對上述對象的處理
關閉上述對象:
finally
{
if?( connection !=?null)
{
if( messageProducer !=?null)
{
try
{
messageProducer.close();
}
catch?( JMSException e2 )
{
log.error("關閉messageProducer異常", e2);
}
}
if( session !=?null)
{
try
{
session.close();
}
catch?( JMSException e2 )
{
log.error("關閉session異常", e2);
}
}
try
{
connection.close();
}
catch?( JMSException e2 )
{
log.error("關閉connection異常", e2);
}
}
}
3.???對事務的處理
3.1.?Spring JMSTemplate對事物的處理方式
3.1.1.????本地事務
Spring為JMS提供了本地事務管理的能力,JMS事務管理器和數據庫事務管理器都是PlatformTransactionManager接口的實現類,Spring的org.springframework.jms.connection包提供了用于管理JMS本地事務JmsTransactionManager事務管理器,JMS1.0.2則對應JmsTransactionManager102。
class=”org.springframework.jms.connection.JmsTransactionManager”>
在進行標準的Spring事務配置后,就能夠管理那些基于JmsTemplate編寫的JMS處理類。對于那些未基于JmsTemplate編寫的JMS處理類,可以讓消息監聽器容器對它們進行事務管理。DefaultMessageListenerContainer和ServerSessionMessageListenerContainer都支持通過消息監聽器使用JMS事務,不過必須為他們提供一個事務管理器,如下配置:
class=”org.springframework.jms.connection.JmsTransactionManager”>
class=”org.springframeword.jms.listener.DefaultMessageListenerContainer”>
3.1.2.????JTA事務
啟用JTA事務后,用戶可以讓數據庫操作、JMS操作以及其它符合JTA標準的操作工作在同一個全局事務中。
對于JMS來說,用戶必須從Java EE的JNDI中獲取XA支持的JMS ConnectionFactory。
對于Spring配置來說,JTA全局事務和本地事務的差別并不大,用戶只需要聲明一個JtaTransactionManager事務管理器,將事務委托給Java EE應用服務器就可以了。當然,ConnectionFactory必須使用XA支持的JMSConnectionFactory。
下面是讓一個數據源和一個JMSConnectionFactory工作于同一個JTA事務的具體配置:
class=”org.springframework.transaction.jta.JtaTransactionManager”/>
3.2.?JMSUtil對事物的處理方式
3.2.1.????本地事務
在Session可以控制交易,首選Session要定義成transacted,然后通過調用commit或rollback來提交或者回滾事務。
QueueSession queueSession
= connection.createQueueSession(boolean transacted, int acknowledgeMode);
TopicSession topicSession
= connection.createTopicSession(Boolean transacted, int acknowledgeMode);
Session.commit();
Session.rollback()
注意:如果transacted = true,則acknowledgeMode的值便無關緊要。
3.2.2.????JTA事務
還不太了解……
4.???不同類型的消息的處理
JMS有多鐘類型的消息:
l??javax.jms.TextMessage
l??javax.jms.MapMessage
l??javax.jms.ObjectMessage
l??javax.jms.BytesMessage
4.1.?Spring使用消息轉換器發送/接收消息
Spring將POJO和JMS消息的雙向轉換工作抽象到MessageConverter中,在JmsTemplate中提供了幾個convertAndSend()和receiveAndConvert()方法,這些方法自動使用MessageConverter完成消息的轉換工作。
4.1.1.????消息轉換器
在org.springframework.jms.support.converter包中,Spring提供了消息轉換器的支持,首先看一下MessageConverter接口的兩個方法:
l??Object fromMessage(Message message)
l??Message toMessage(Object object, Session session)
MessageConverter接口的目的是為了向調用者屏蔽JMS細節,在JMS之上搭建的一個隔離層,這樣調用者可以直接發送和接收POJO,而不是發送和接收JMS相關消息,調用者的程序將得到進一步簡化。
JMS消息類型
POJO類型
javax.jms.TextMessage
String
javax.jms.MapMessage
java.util.Map
javax.jms.ObjectMessage
java.io.Serializable
javax.jms.BytesMessage
byte[] bytes
當轉換發生錯誤時,Spring將拋出MessageConversionException異常,該異常是org.springframework.jms.JmsException的子類。
JmsTemplate和JmsTemplate102分別使用SimpleMessageConverter和SimpleMessageConverter102作為默認的消息轉換器。用戶也可以通過實現MessageConverter定義自己的消息轉換器,并在配置JmsTemplate時通過messageConverter屬性指定自己的消息轉換器。
4.1.2.????發送POJO消息
4.1.2.1.???????將POJO簡單地映射為Message對象發送
假設User是一個POJO,其結構如下:
package com.baobaotao.domain;
……
public class User?implement Serializable
{
private String username;
private String userId;
private String email;
private int level;
//?省略get/setter
}
這個POJO必須實現Serializable接口,以便可以將對象序列化后作為消息發送,除此以外沒有任何其他的要求。
將User作為JMS消息發送的操作僅需要一行簡單的代碼就可以完成:
package com.baobaotao.jms;
……
import com.baobaotao.domain.User;
public class MessageSender extends JmsGatewaySupport
{
……
public void sendUserMsg(User user)
{
//發送User對象
super.getJmsTemplate.convertAndSend(“userMsgQ”, user);
}
}
JmsTemplate提供了幾個重載版本的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后進行后置處理
通過以上方法發送POJO,JmsTemplate僅會按照簡單的映射方式發送JMS消息,如果我們需要在此基礎上進一步設置Message的Header和Properties部分的值,一種方法是編寫自己的消息轉換器達到目的,還有一種更好的方法是使用Spring的org.springframework.jms.core.MessagePostProcessor回調接口。JmsTemplate在使用MessageConverter將POJO轉換為JMS消息后以及發送消息前,將調用MessagePostProcessor對JMS消息進行后置加工處理。因此,我們有機會通過一個自定義的MessagePostProcessor回調接口對JMS消息對象進行“修正性”工作。
下面,我們在User轉換為ObjectMessage后,為消息對象指定過期時間并設置一個屬性:
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); //設置過期時間:一小時后過期
message.setIntProperty(“level”, user.getLevel()); //?設置一個屬性
}
});
}
}
4.1.3.????接收POJO消息
4.2.?JMSUtil必須直接實例化不同類型的消息對象
4.2.1.????發送消息
例如,如果要發送的消息是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?運行時異常
JMS的異常都是檢查型異常,使用原生JMS API,用戶需要提供繁瑣的異常捕獲代碼。而Spring將檢查型異常轉化為運行期異常。
Spring在org.springframework.jms包為javax.jms包中所有的異常類提供了類型轉換的鏡像實現。如:org.springframework.jms.IllegalStateException對應javax.jms.IllegalStateExceptipn;org.springframework.jms.InvalidClientIDException對應javax.jms.InvalidClientIDException等。Spring中所有JMS相關的異常都繼承于JmsException類。
此外,Spring還提供了一些特定的JMS異常類:
l??DestinationResolutionException:Spring允許通過簡單的字符串指定消息地址,DestinationResolver在解析消息地址發生錯誤時拋出異常;
l??SynchedLocalTransactionFailedException:如果在同步本地事務發生異常時拋出該異常,由于事務已經結束后,再次嘗試同步事務時會發生這個異常;
l??UncategorizedJmsException:任何未被歸類的其他類型一場。
5.2.?JMSUtil檢查異常
總結
以上是生活随笔為你收集整理的java 配置jmstemplate_Spring JMSTemplate 与 JMS 原生API比较的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python不支持的数据类型有achar
- 下一篇: gradle idea java ssm