1.4     消息转换器MessageConverter

MessageConverter的作用主要有双方面,一方面它能够把我们的非标准化Message对象转换成我们的目标Message对象,这主要是用在发送消息的时候;还有一方面它又能够把我们的Message对象转换成相应的目标对象,这主要是用在接收消息的时候。

以下我们就拿发送一个对象消息来举例,如果我们有这样一个需求:我们平台有一个发送邮件的功能,进行发送的时候我们仅仅是把我们的相关信息封装成一个JMS消息,然后利用JMS进行发送,在相应的消息监听器进行接收到的消息处理时才真正的进行消息发送。

如果我们有这么一个Email对象:

public class Email implements Serializable {

    private static final long serialVersionUID = -658250125732806493L;

    private String receiver;
private String title;
private String content; public Email(String receiver, String title, String content) {
this.receiver = receiver;
this.title = title;
this.content = content;
} public String getReceiver() {
return receiver;
} public void setReceiver(String receiver) {
this.receiver = receiver;
} public String getTitle() {
return title;
} public void setTitle(String title) {
this.title = title;
} public String getContent() {
return content;
} public void setContent(String content) {
this.content = content;
} @Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Email [receiver=").append(receiver).append(", title=")
.append(title).append(", content=").append(content).append("]");
return builder.toString();
} }

这个Email对象包括了一个简单的接收者email地址、邮件主题和邮件内容。我们在发送的时候就把这个对象封装成一个ObjectMessage进行发送。代码例如以下所看到的:

public class ProducerServiceImpl implements ProducerService {

    @Autowired
private JmsTemplate jmsTemplate; public void sendMessage(Destination destination, final Serializable obj) {
jmsTemplate.send(destination, new MessageCreator() { public Message createMessage(Session session) throws JMSException {
ObjectMessage objMessage = session.createObjectMessage(obj);
return objMessage;
} });
} }

这是相应的在没有使用MessageConverter的时候我们须要new一个MessageCreator接口对象,然后在其抽象方法createMessage内部使用session创建一个相应的消息。

在使用了MessageConverter的时候我们在使用JmsTemplate进行消息发送时仅仅须要调用其相应的convertAndSend方法就可以。

如:

    public void sendMessage(Destination destination, final Serializable obj) {
//未使用MessageConverter的情况
/*jmsTemplate.send(destination, new MessageCreator() { public Message createMessage(Session session) throws JMSException {
ObjectMessage objMessage = session.createObjectMessage(obj);
return objMessage;
} });*/
//使用MessageConverter的情况
jmsTemplate.convertAndSend(destination, obj);
}

这样JmsTemplate就会在其内部调用预定的MessageConverter对我们的消息对象进行转换。然后再进行发送。

这个时候我们就须要定义我们的MessageConverter了。

要定义自己的MessageConverter非常easy。仅仅须要实现Spring为我们提供的MessageConverter接口就可以。我们先来看一下MessageConverter接口的定义:

public interface MessageConverter {

    Message toMessage(Object object, Session session) throws JMSException, MessageConversionException;

    Object fromMessage(Message message) throws JMSException, MessageConversionException;

}

我们能够看到当中一共定义了两个方法fromMessage和toMessage,fromMessage是用来把一个JMS
Message转换成相应的Java对象,而toMessage方法是用来把一个Java对象转换成相应的JMS
Message。由于我们已经知道上面要发送的对象就是一个Email对象。所以在这里我们就简单地定义一个EmailMessageConverter用来把Email对象和相应的ObjectMessage进行转换,其代码例如以下:

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.ObjectMessage;
import javax.jms.Session; import org.springframework.jms.support.converter.MessageConversionException;
import org.springframework.jms.support.converter.MessageConverter; public class EmailMessageConverter implements MessageConverter { public Message toMessage(Object object, Session session)
throws JMSException, MessageConversionException {
return session.createObjectMessage((Serializable) object);
} public Object fromMessage(Message message) throws JMSException,
MessageConversionException {
ObjectMessage objMessage = (ObjectMessage) message;
return objMessage.getObject();
} }

这样当我们利用JmsTemplate的convertAndSend方法发送一个Email对象的时候就会把相应的Email对象当做參数调用我们定义好的EmailMessageConverter的toMessage方法。

定义好我们的EmailMessageConverter之后就须要指定我们用来发送Email对象的JmsTemplate对象的messageConverter为EmailMessageConverter。这里我们在Spring的配置文件里定义JmsTemplate bean的时候就指定:

    <!-- Spring提供的JMS工具类。它可以进行消息发送、接收等 -->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<!-- 这个connectionFactory相应的是我们定义的Spring提供的那个ConnectionFactory对象 -->
<property name="connectionFactory" ref="connectionFactory"/>
<!-- 消息转换器 -->
<property name="messageConverter" ref="emailMessageConverter"/>
</bean>
<!-- 类型转换器 -->
<bean id="emailMessageConverter" class="com.tiantian.springintejms.converter.EmailMessageConverter"/>

到此我们的MessageConverter就定义好了。也可以进行使用了,接着我们来进行測试一下,定义測试代码例如以下所看到的:

    @Test
public void testObjectMessage() {
Email email = new Email("zhangsan@xxx.com", "主题", "内容");
producerService.sendMessage(destination, email);
}

上面destination相应的接收处理的MessageListener方法例如以下所看到的:

public class ConsumerMessageListener implements MessageListener {

    public void onMessage(Message message) {

        if (message instanceof ObjectMessage) {
ObjectMessage objMessage = (ObjectMessage) message;
try {
Object obj = objMessage.getObject();
Email email = (Email) obj;
System.out.println("接收到一个ObjectMessage,包括Email对象。 ");
System.out.println(email);
} catch (JMSException e) {
e.printStackTrace();
}
}
} }

之前说了MessageConverter有双方面的功能,除了把Java对象转换成相应的Jms
Message之外还能够把Jms
Message转换成相应的Java对象。我们看上面的消息监听器在接收消息的时候接收到的就是一个Jms
Message,假设我们要利用MessageConverter来把它转换成相应的Java对象的话。仅仅能是我们往里面注入一个相应的MessageConverter,然后在里面手动的调用。如:

public class ConsumerMessageListener implements MessageListener {

    private MessageConverter messageConverter;

    public void onMessage(Message message) {

        if (message instanceof ObjectMessage) {
ObjectMessage objMessage = (ObjectMessage) message;
try {
/*Object obj = objMessage.getObject();
Email email = (Email) obj;*/
Email email = (Email) messageConverter.fromMessage(objMessage);
System.out.println("接收到一个ObjectMessage,包括Email对象。 ");
System.out.println(email);
} catch (JMSException e) {
e.printStackTrace();
} }
} public MessageConverter getMessageConverter() {
return messageConverter;
} public void setMessageConverter(MessageConverter messageConverter) {
this.messageConverter = messageConverter;
} }

当我们使用MessageListenerAdapter来作为消息监听器的时候,我们能够为它指定一个相应的MessageConverter,这样Spring在处理接收到的消息的时候就会自己主动地利用我们指定的MessageConverter对它进行转换,然后把转换后的Java对象作为參数调用指定的消息处理方法。这里我们再把前面解说MessageListenerAdapter时定义的MessageListenerAdapter拿来做一个測试,我们指定它的MessageConverter为我们定义好的EmailMessageConverter。

    <!-- 消息监听适配器 -->
<bean id="messageListenerAdapter" class="org.springframework.jms.listener.adapter.MessageListenerAdapter">
<property name="delegate">
<bean class="com.tiantian.springintejms.listener.ConsumerListener"/>
</property>
<property name="defaultListenerMethod" value="receiveMessage"/>
<property name="messageConverter" ref="emailMessageConverter"/>
</bean>
<!-- 消息监听适配器相应的监听容器 -->
<bean id="messageListenerAdapterContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destination" ref="adapterQueue"/>
<property name="messageListener" ref="messageListenerAdapter"/><!-- 使用MessageListenerAdapter来作为消息监听器 -->
</bean>

然后在我们的真正用于处理接收到的消息的ConsumerListener中加入一个receiveMessage方法。加入后其代码例如以下所看到的:

public class ConsumerListener {

    public void receiveMessage(String message) {
System.out.println("ConsumerListener通过receiveMessage接收到一个纯文本消息,消息内容是:" + message);
} public void receiveMessage(Email email) {
System.out.println("接收到一个包括Email的ObjectMessage。");
System.out.println(email);
} }

然后我们定义例如以下測试代码:

    @Test
public void testObjectMessage() {
Email email = new Email("zhangsan@xxx.com", "主题", "内容");
producerService.sendMessage(adapterQueue, email);
}

由于我们给MessageListenerAdapter指定了一个MessageConverter,并且是一个EmailMessageConverter,所以当MessageListenerAdapter接收到一个消息后。它会调用我们指定的MessageConverter的fromMessage方法把它转换成一个Java对象。依据定义这里会转换成一个Email对象。然后会把这个Email对象作为參数调用我们通过defaultListenerMethod属性指定的默认处理器方法,依据定义这里就是receiveMessage方法,可是我们能够看到在ConsumerListener中我们一共定义了两个receiveMessage方法,由于是通过转换后的Email对象作为參数进行方法调用的,所以这里调用的就应该是參数类型为Email的receiveMessage方法了。上述測试代码执行后会输出例如以下结果:

讲到这里可能有读者就会有疑问了,说我们在之前解说MessageListenerAdapter的时候不是没有指定相应的MessageConverter,然后发送了一个TextMessage,结果Spring还是把它转换成一个String对象,调用了ConsumerListener參数类型为String的receiveMessage方法吗?那你这个MessageConverter在MessageListenerAdapter进行消息接收的时候也没什么用啊。

事实上还是实用的。在我们使用MessageListenerAdapter时,在对其进行初始化也就是调用其构造方法时。它会默认new一个Spring已经为我们实现了的MessageConverter——SimpleMessageConverter作为其默认的MessageConverter,这也就是为什么我们在使用MessageListenerAdapter的时候不须要指定MessageConverter可是消息还是会转换成相应的Java对象的原因。所以默认情况下我们使用MessageListenerAdapter时其相应的MessageListener的处理器方法參数类型必须是一个普通Java对象,而不能是相应的Jms
Message对象。

那假设我们在处理Jms Message的时候想使用MessageListenerAdapter,然后又希望处理最原始的Message,而不是经过MessageConverter进行转换后的Message该怎么办呢?这个时候我们仅仅须要在定义MessageListenerAdapter的时候指定其MessageConverter为空就能够了。

    <!-- 消息监听适配器 -->
<bean id="messageListenerAdapter" class="org.springframework.jms.listener.adapter.MessageListenerAdapter">
<property name="delegate">
<bean class="com.tiantian.springintejms.listener.ConsumerListener"/>
</property>
<property name="defaultListenerMethod" value="receiveMessage"/>
<property name="messageConverter">
<null/>
</property>
</bean>

那么这个时候我们的真实MessageListener的处理器方法參数类型就应该是Jms
Message或相应的Jms
Message子类型了,不然就会调用不到相应的处理方法了。这里由于我们发送的是一个ObjectMessage。所以这里就加入一个相应的參数类型为ObjectMessage的receiveMessage方法了。

    public void receiveMessage(ObjectMessage message) throws JMSException {
System.out.println(message.getObject());
}

刚刚讲到Spring已经为我们实现了一个简单的MessageConverter。即org.springframework.jms.support.converter.SimpleMessageConverter,事实上Spring在初始化JmsTemplate的时候也指定了其相应的MessageConverter为一个SimpleMessageConverter,所以假设我们寻常没有什么特殊要求的时候能够直接使用JmsTemplate的convertAndSend系列方法进行消息发送。而不必繁琐的在调用send方法时自己new一个MessageCreator进行相应Message的创建。

这里我们也来看一下SimpleMessageConverter的定义,假设认为它不能满足你的要求,那我们能够对它里面的部分方法进行重写,或者是全然实现自己的MessageConverter。

public class SimpleMessageConverter implements MessageConverter {

    public Message toMessage(Object object, Session session) throws JMSException, MessageConversionException {
if (object instanceof Message) {
return (Message) object;
}
else if (object instanceof String) {
return createMessageForString((String) object, session);
}
else if (object instanceof byte[]) {
return createMessageForByteArray((byte[]) object, session);
}
else if (object instanceof Map) {
return createMessageForMap((Map) object, session);
}
else if (object instanceof Serializable) {
return createMessageForSerializable(((Serializable) object), session);
} else {
throw new MessageConversionException("Cannot convert object of type [" +
ObjectUtils.nullSafeClassName(object) + "] to JMS message. Supported message " +
"payloads are: String, byte array, Map<String,?>, Serializable object.");
}
} public Object fromMessage(Message message) throws JMSException, MessageConversionException {
if (message instanceof TextMessage) {
return extractStringFromMessage((TextMessage) message);
}
else if (message instanceof BytesMessage) {
return extractByteArrayFromMessage((BytesMessage) message);
}
else if (message instanceof MapMessage) {
return extractMapFromMessage((MapMessage) message);
}
else if (message instanceof ObjectMessage) {
return extractSerializableFromMessage((ObjectMessage) message);
}
else {
return message;
}
} protected TextMessage createMessageForString(String text, Session session) throws JMSException {
return session.createTextMessage(text);
} protected BytesMessage createMessageForByteArray(byte[] bytes, Session session) throws JMSException {
BytesMessage message = session.createBytesMessage();
message.writeBytes(bytes);
return message;
} protected MapMessage createMessageForMap(Map<?, ? > map, Session session) throws JMSException {
MapMessage message = session.createMapMessage();
for (Map.Entry entry : map.entrySet()) {
if (!(entry.getKey() instanceof String)) {
throw new MessageConversionException("Cannot convert non-String key of type [" +
ObjectUtils.nullSafeClassName(entry.getKey()) + "] to JMS MapMessage entry");
}
message.setObject((String) entry.getKey(), entry.getValue());
}
return message;
} protected ObjectMessage createMessageForSerializable(Serializable object, Session session) throws JMSException {
return session.createObjectMessage(object);
} protected String extractStringFromMessage(TextMessage message) throws JMSException {
return message.getText();
} protected byte[] extractByteArrayFromMessage(BytesMessage message) throws JMSException {
byte[] bytes = new byte[(int) message.getBodyLength()];
message.readBytes(bytes);
return bytes;
} protected Map extractMapFromMessage(MapMessage message) throws JMSException {
Map<String, Object> map = new HashMap<String, Object>();
Enumeration en = message.getMapNames();
while (en.hasMoreElements()) {
String key = (String) en.nextElement();
map.put(key, message.getObject(key));
}
return map;
} protected Serializable extractSerializableFromMessage(ObjectMessage message) throws JMSException {
return message.getObject();
} }

Spring整合Jms学习(三)_MessageConverter介绍的更多相关文章

  1. Spring整合JMS(二)——三种消息监听器

    原文地址:http://haohaoxuexi.iteye.com/blog/1893676 1.3     消息监听器MessageListener 在Spring整合JMS的应用中我们在定义消息监 ...

  2. Spring整合JMS(二)——三种消息监听器(转)

    *注:别人那复制来的 1.3     消息监听器MessageListener 在Spring整合JMS的应用中我们在定义消息监听器的时候一共可以定义三种类型的消息监听器,分别是MessageList ...

  3. Spring整合JMS(三)——MessageConverter介绍

    原文链接:http://haohaoxuexi.iteye.com/blog/1900937 1.4     消息转换器MessageConverter MessageConverter的作用主要有两 ...

  4. Spring整合JMS(三)——MessageConverter介绍(转)

    *注:别人那复制来的 1.4     消息转换器MessageConverter MessageConverter的作用主要有两方面,一方面它可以把我们的非标准化Message对象转换成我们的目标Me ...

  5. ActiveMQ (三) Spring整合JMS入门

    Spring整合JMS入门 前提:安装好了ActiveMQ  ActiveMQ安装 Demo结构:   生产者项目springjms_producer: pom.xml <?xml versio ...

  6. Spring整合JMS(一)——基于ActiveMQ实现 (转)

    *注:别人那复制来的 1.1     JMS简介 JMS的全称是Java Message Service,即Java消 息服务.它主要用于在生产者和消费者之间进行消息传递,生产者负责产生消息,而消费者 ...

  7. 消息中间件ActiveMQ及Spring整合JMS

    一 .消息中间件的基本介绍 1.1 消息中间件 1.1.1 什么是消息中间件 消息中间件利用高效可靠的消息传递机制进行平台无关的数据交流,并基于数据通信来进行分布式系统的集成.通过提供消息传递和消息排 ...

  8. Spring Boot 项目学习 (三) Spring Boot + Redis 搭建

    0 引言 本文主要介绍 Spring Boot 中 Redis 的配置和基本使用. 1 配置 Redis 1. 修改pom.xml,添加Redis依赖 <!-- Spring Boot Redi ...

  9. Spring整合JMS(一)——基于ActiveMQ实现

    1.1     JMS简介 JMS的全称是Java Message Service,即Java消息服务.它主要用于在生产者和消费者之间进行消息传递,生产者负责产生消息,而消费者负责接收消息.把它应用到 ...

随机推荐

  1. sql: update from

    sql server提供了update的from 子句,可以将要更新的表与其它的数据源连接起来.虽然只能对一个表进行更新,但是通过将要更新的表与其它的数据源连接起来,就可以在update的表达式 中引 ...

  2. 屏蔽EditText长按导致的弹出输入法的对话框

    做了个能手动拖动的EditText,但有个问题导致的体验很不好,就是手放上去开始拖,拖到一段距离后弹出个输入法的对话框,这根本不是我想要的效果,于是就想屏蔽它,结果在网上找到一句代码,放上去 顿时解决 ...

  3. Android来电监听

    本文实现来电自动接听,自动录音,自动回拨功能. public class MainActivity extends Activity { @Override protected void onCrea ...

  4. Nginx负载均衡:分布式/热备Web Server的搭建

    Nginx是一款轻量级的Web server/反向代理server及电子邮件(IMAP/POP3)代理server.并在一个BSD-like 协议下发行.由俄罗斯的程序设计师Igor Sysoev所开 ...

  5. 如果一个Object对象可能是数组那么如何对其进行迭代

    需求:一个方法传入的参数是Object类型(假设对象为“items”,使用Object类型也是为了使用多态而增加方法复用性),但已知这个Object对象可能是基本类型数组,也可能是对象数组,如何将这个 ...

  6. K. Perpetuum Mobile

    The world famous scientist Innokentiy almost finished the creation of perpetuum mobile. Its main par ...

  7. 基于visual Studio2013解决面试题之0202上下排

     题目

  8. POJ 2632 Crashing Robots (坑爹的模拟题)

    Crashing Robots Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6599   Accepted: 2854 D ...

  9. 华为OJ培训主题 比赛统计

    题目例如以下: 比赛情况统计 有一个游戏平台,各个參赛队伍(以唯一的TeamID来标识)之间进行单循环的对抗赛,两个队伍之间仅仅举行一场比赛,比赛以得分的多少定胜负.须要完毕一个统计赛况的程序,可以随 ...

  10. Ajax - 登录

    Login.html <head> <title>登录</title> <mce:script src="js/jquery-1.5.2.js&qu ...