`

Spring整合JMS(三)——MessageConverter消息转换器

    博客分类:
  • JMS
阅读更多

一、ActiveMQ入门实例

二、Spring整合JMS(一)——基于ActiveMQ实现

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

四、Spring整合JMS(三)——MessageConverter消息转换器

五、Spring整合JMS(四)——事务管理

 

 消息转换器MessageConverter

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

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

假设我们有这么一个Email对象:

 

package cn.tzz.jms.activemq.spring.obj;

import java.io.Serializable;

public class Email implements Serializable {
	 
	private static final long serialVersionUID = 1L;
	
	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() {
		return "Email [receiver=" + receiver + ", title=" + title
				+ ", content=" + content + "]";
	}
    
}

  

 

 这个Email对象包含了一个简单的接收者email地址、邮件主题和邮件内容。我们在发送的时候就把这个对象封装成一个ObjectMessage进行发送,使用MessageConverter的时候我们在使用JmsTemplate进行消息发送时只需要调用其对应的convertAndSend方法即可。代码如下所示:
import java.io.Serializable;
import javax.jms.Destination;

public interface EntityProducerService {

	public void sendMessage(Destination destination, final Serializable obj);
}
 
import java.io.Serializable;

import javax.jms.Destination;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Service;

import cn.tzz.jms.activemq.spring.obj.service.EntityProducerService;
 
 
@Service(value="entityProducerService")
public class EntityProducerServiceImpl implements EntityProducerService {
 
	@Autowired
    private JmsTemplate jmsTemplate;
    
    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很简单,只需要实现Spring为我们提供的MessageConverter接口即可。我们先来看一下Spring  MessageConverter接口的定义:

 

public interface MessageConverter {

	Message toMessage(Object object, Session session);
	Object fromMessage(Message message);
}
 我们可以看到其中一共定义了两个方法fromMessage和toMessage,fromMessage是用来把一个JMS Message转换成对应的Java对象,而toMessage方法是用来把一个Java对象转换成对应的JMS Message。因为我们已经知道上面要发送的对象就是一个Email对象,所以在这里我们就简单地定义一个EmailMessageConverter用来把Email对象和对应的ObjectMessage进行转换,其代码如下:
import java.io.Serializable;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.ObjectMessage;
import javax.jms.Session;

import org.springframework.jms.support.converter.MessageConverter;

public class EmailMessageConverter implements MessageConverter {

	public Message toMessage(Object object, Session session) {
		ObjectMessage objectMessage = null;
		try {
			objectMessage = session.createObjectMessage((Serializable) object);
		} catch (JMSException e) {
			e.printStackTrace();
		}
		return objectMessage;
	}

	public Object fromMessage(Message message) {
		ObjectMessage objMessage = null;
		Serializable serializable = null;
		try {
			objMessage = (ObjectMessage) message;
			serializable = objMessage.getObject();
		} catch (JMSException e) {
			e.printStackTrace();
		}
		return serializable;
	}
}

 

       这样当我们利用JmsTemplateconvertAndSend方法发送一个Email对象的时候就会把对应的Email对象当做参数调用我们定义好的EmailMessageConvertertoMessage方法。

       定义好我们的EmailMessageConverter之后就需要指定我们用来发送Email对象的JmsTemplate对象的messageConverterEmailMessageConverter,这里我们在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="cn.tzz.jms.activemq.spring.obj.service.impl.EmailMessageConverter"/>  
 

 

 到此我们的MessageConverter就定义好了,也能够进行使用了.

       上面destination对应的接收处理的MessageListener方法如下所示:

 

 
public class ConsumerObjMessageListener 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,然后在里面手动的调用,如:

 

 
package cn.tzz.jms.activemq.spring.listener;

import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;

import org.springframework.jms.support.converter.MessageConverter;

import cn.tzz.jms.activemq.spring.obj.Email;

public class ConsumerObjMessageListener implements MessageListener {

	private MessageConverter emailMessageConverter;

	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) emailMessageConverter.fromMessage(objMessage); 
				System.out.println("ConsumerObjMessageListener");
				System.out.println("接收到一个ObjectMessage,包含Email对象。");
				System.out.println(email);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	public MessageConverter getEmailMessageConverter() {
		return emailMessageConverter;
	}

	public void setEmailMessageConverter(MessageConverter emailMessageConverter) {
		this.emailMessageConverter = emailMessageConverter;
	}
}
 

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

 

 
 <context:annotation-config />
	<context:component-scan base-package="cn.tzz.jms.activemq.spring.obj" />
		
	<!-- ActiveMQ -->
	<!-- 真正可以产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供-->
    <bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
        <property name="brokerURL" value="tcp://localhost:61616"/>
    </bean>
    <bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory">
        <property name="connectionFactory" ref="targetConnectionFactory"/>
        <property name="maxConnections" value="10"/>
    </bean>
    <bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory">
        <property name="targetConnectionFactory" ref="pooledConnectionFactory"/>
    </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="queueDestination" class="org.apache.activemq.command.ActiveMQQueue">
		<constructor-arg>
			<value>queue</value>
		</constructor-arg>
	</bean>
	<!--这个是主题目的地,一对多的 -->
	<bean id="topicDestination" class="org.apache.activemq.command.ActiveMQTopic">
		<constructor-arg value="topic" />
	</bean>
	
    <bean id="adapterQueue" class="org.apache.activemq.command.ActiveMQQueue">  
        <constructor-arg>  
            <value>adapterQueue</value>  
        </constructor-arg>  
    </bean>  
   
	<!-- 类型转换器 -->  
	<bean id="emailMessageConverter" class="cn.tzz.jms.activemq.spring.obj.service.impl.EmailMessageConverter"/>  
	
	<!-- 自定义消息监听 -->
    <bean id="consumerObjMessageListener" class="cn.tzz.jms.activemq.spring.listener.ConsumerObjMessageListener">
    	<property name="emailMessageConverter" ref="emailMessageConverter"/>  
    </bean>
	
	<!-- MessageListenerAdapter 消息监听 -->
    <bean id="objMessageListenerAdapter" class="org.springframework.jms.listener.adapter.MessageListenerAdapter">
        <property name="delegate">
            <bean class="cn.tzz.jms.activemq.spring.listener.ConsumerListener"/>
        </property>
        <property name="defaultListenerMethod" value="receiveMessage"/>
        <property name="messageConverter" ref="emailMessageConverter"/>
    </bean>
    
    <!-- 消息监听适配器对应的监听容器 -->
    <bean id="objMessageListenerAdapterContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory" ref="connectionFactory"/>
        <property name="destination" ref="adapterQueue"/>
<!--         <property name="messageListener" ref="objMessageListenerAdapter"/> -->
        <property name="messageListener" ref="consumerObjMessageListener"/>
    </bean>
 

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

 

public class ConsumerListener {
 
    public void handleMessage(String message) {
        System.out.println("ConsumerListener通过handleMessage接收到消息:" + message);
    }
//    public void receiveMessage(String message) {
//        System.out.println("ConsumerListener通过receiveMessage接收到消息:" + message);
//    }
//    public String receiveMessage(String message) {
//    	System.out.println("ConsumerListener通过receiveMessage接收到消息:" + message);
//    	return "这是ConsumerListener对象的receiveMessage方法的返回值。";  
//    }
    
    public void receiveMessage(Email email) {  
        System.out.println("接收到一个包含Email的ObjectMessage。");  
        System.out.println(email);  
    }  
}
 

       然后我们定义如下测试代码:

 

 
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/applicationContext2.xml")
public class EntiryProducerConsumerTest {

	@Resource(name="entityProducerService")
	private EntityProducerService entityProducerService;
	@Autowired  
    @Qualifier("adapterQueue")  
	private Destination adapterQueue;  
	  
    @Test  
    public void testObjectMessage() {
        Email email = new Email("test@qq.com", "测试", "HellWorld");
        entityProducerService.sendMessage(adapterQueue, email);
    }
}
 

       因为我们给MessageListenerAdapter指定了一个MessageConverter,而且是一个EmailMessageConverter,所以当MessageListenerAdapter接收到一个消息后,它会调用我们指定的MessageConverter的fromMessage方法把它转换成一个Java对象,根据定义这里会转换成一个Email对象,然后会把这个Email对象作为参数调用我们通过defaultListenerMethod属性指定的默认处理器方法,根据定义这里就是receiveMessage方法,但是我们可以看到在ConsumerListener中我们一共定义了两个receiveMessage方法,因为是通过转换后的Email对象作为参数进行方法调用的,所以这里调用的就应该是参数类型为Email的receiveMessage方法了。

上述测试代码运行后会输出如下结果:

接收到一个ObjectMessage,包含Email对象。

Email [receiver=test@qq.com, title=测试, content=HellWorld]


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

       其实还是有用的,在我们使用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,所以这里就添加一个对应的参数类型为ObjectMessagereceiveMessage方法了。

 

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

 

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

 

分享到:
评论

相关推荐

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

    NULL 博文链接:https://elim.iteye.com/blog/1900937

    JMS入门Demo

    在Spring整合JMS的应用中,如果我们要进行本地的事务管理的话非常简单,只需要在定义对应的消息监听容器时指定其sessionTransacted属性为true,如: &lt;bean id="jmsContainer" class="org.springframework.jms....

    基于springboot集成mybatis、durid和自定义消息转换项目

    基于springboot集成mybatis、durid和自定义消息转换项目,实现阿里巴巴的durid对数据库连接池的设置和自定义消息转换的messageconverter,能够快速开发自己的应用。

    spring-cloud-stream-rabbit

    春云流兔Spring Cloud Stream示例展示了各种消息交换模式。 该项目基于Baeldung构建的SCS示例,并进行了修改以与Elmhurst版本或更高版本一起使用。 示例包括: MessageConverter:样本处理器应用程序,它接收一条...

    SPRING API 2.0.CHM

    MessageConverter MessageCreator MessageEOFException MessageFormatException MessageListenerAdapter MessageListenerAdapter102 MessageNotReadableException MessageNotWriteableException ...

    springmvc log4j2 logback 注解 jackson 日志脱敏实现源码

    几乎是网上 能找到的 日志脱敏的所有实现 1、基于正则表达式的 日志脱敏实现 ,扩展logback 、log4j 2、springmvc 返回报文脱敏。 3、基于注解方式的脱敏。 大家选择使用。

    excel-parser-spring-boot-starter:Excel解析器

    Excel解析器 Excel Parser提供了一个功能,可以轻松地从Spring引导应用程序中提取Excel数据。 使用Apache POI库对API进行了抽象,并且通过使用Excel Parser,用户可以专注于编写业务逻辑。 同时支持DOM类型...

    zxs:洲鑫系统

    json 客户监听器模式hystrix工作方式kafka kafka api 流简单实现验证别名注释注解派生aop切面,过滤器,拦截器安全resttemplate自定义restTemplate 拼写作用域resttemplate自定义其余MessageConverter数据格式转换编...

    自定义日志脱敏组件,简单3 步完成 Spring Boot 的日志脱敏

    对于日志脱敏的方式有很多,常见的有①使用conversionRule标签,继承MessageConverter②书写一个脱敏工具类,在打印日志的时候对特定特字段进行脱敏返回。 两种方式各有优缺点:第一种方式需要修改代码,不符合开闭...

    lucene-test

    相当于注册了DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter两个bean, 配置一些messageconverter。即解决了@Controller注解的使用前提配置。

    annotation.txt

    配置一些messageconverter。即解决了@Controller注解的使用前提配置是对包进行扫描,实现注释驱动Bean定义,同时将bean自动注入容器中使用。即解决了@Controller标识的类的bean的注入和使用。 

    vizix-kafka-connect-rabbitmq

    在Eclipse中导入项目 确保bin / io / confluent / connect / rabbitmq / MessageConverter.class已编译 运行path.sh以在out / kafka-connect-rabbitmq-1.0.0-preview_patch.jar中生成修补的lib

Global site tag (gtag.js) - Google Analytics