1,消息监听容器java
对于消息监听容器而言,除了要知道监听哪一个目的地以外,还须要知道到哪里去监听,也就是说它还须要知道去监听哪一个JMS服务器,这是经过在配置MessageConnectionFactory的时候往里面注入一个ConnectionFactory来实现的。因此咱们在配置一个MessageListenerContainer的时候有三个属性必须指定,一个是表示从哪里监听的ConnectionFactory;一个是表示监听什么的Destination;一个是接收到消息之后进行消息处理的MessageListener。Spring一共为咱们提供了两种类型的MessageListenerContainer,SimpleMessageListenerContainer和DefaultMessageListenerContainer。spring
SimpleMessageListenerContainer会在一开始的时候就建立一个会话session和消费者Consumer,而且会使用标准的JMS MessageConsumer.setMessageListener()方法注册监听器让JMS提供者调用监听器的回调函数。它不会动态的适应运行时须要和参与外部的事务管理。兼容性方面,它很是接近于独立的JMS规范,但通常不兼容Java EE的JMS限制。apache
大多数状况下咱们仍是使用的DefaultMessageListenerContainer,跟SimpleMessageListenerContainer相比,DefaultMessageListenerContainer会动态的适应运行时须要,而且可以参与外部的事务管理。它很好的平衡了对JMS提供者要求低、先进功能如事务参与和兼容Java EE环境。数组
2.消息监听器服务器
在spring整合JMS的应用中咱们在定义消息监听器的时候一共能够定义三种类型的消息监听器,分别是MessageListener、SessionAwareMessageListener和MessageListenerAdapter。下面就分别来介绍一下这几种类型的区别。session
MessageListener是最原始的消息监听器,它是JMS规范中定义的一个接口。其中定义了一个用于处理接收到的消息的onMessage方法,该方法只接收一个Message参数。函数
import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageListener; import javax.jms.TextMessage; public class ConsumerMessageListener implements MessageListener { public void onMessage(Message message) { //这里咱们知道生产者发送的就是一个纯文本消息,因此这里能够直接进行强制转换,或者直接把onMessage方法的参数改为Message的子类TextMessage TextMessage textMsg = (TextMessage) message; System.out.println("接收到一个纯文本消息。"); try { System.out.println("消息内容是:" + textMsg.getText()); } catch (JMSException e) { e.printStackTrace(); } } }
SessionAwareMessageListener是Spring为咱们提供的,它不是标准的JMS MessageListener。MessageListener的设计只是纯粹用来接收消息的,假如咱们在使用MessageListener处理接收到的消息时咱们须要发送一个消息通知对方咱们已经收到这个消息了,那么这个时候咱们就须要在代码里面去从新获取一个Connection或Session。SessionAwareMessageListener的设计就是为了方便咱们在接收到消息后发送一个回复的消息,它一样为咱们提供了一个处理接收到的消息的onMessage方法,可是这个方法能够同时接收两个参数,一个是表示当前接收到的消息Message,另外一个就是能够用来发送消息的Session对象。测试
public void onMessage(TextMessage message, Session session) throws JMSException { System.out.println("收到一条消息"); System.out.println("消息内容是:" + message.getText()); MessageProducer producer = session.createProducer(destination); Message textMessage = session.createTextMessage("ConsumerSessionAwareMessageListener。。。"); producer.send(textMessage); }
MessageListenerAdapter类实现了MessageListener接口和SessionAwareMessageListener接口,它的主要做用是将接收到的消息进行类型转换,而后经过反射的形式把它交给一个普通的Java类进行处理。 其另一个主要的功能是能够自动的发送返回消息。spa
MessageListenerAdapter会把接收到的消息作以下转换:.net
TextMessage转换为String对象;
BytesMessage转换为byte数组;
MapMessage转换为Map对象;
ObjectMessage转换为对应的Serializable对象。
<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"/> </bean> //或者 <bean id="messageListenerAdapter" class="org.springframework.jms.listener.adapter.MessageListenerAdapter"> <constructor-arg> <bean class="com.tiantian.springintejms.listener.ConsumerListener"/> </constructor-arg> <property name="defaultListenerMethod" value="receiveMessage"/> </bean>
消息回复:
(1),能够经过发送的Message的setJMSReplyTo方法指定该消息对应的回复消息的目的地。 这里咱们把咱们的生产者发送消息的代码作一下修改,在发送消息以前先指定该消息对应的回复目的地为一个叫responseQueue的队列目的地,具体代码以下所示:
package com.tiantian.springintejms.service.impl; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.Session; import javax.jms.TextMessage; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.jms.core.JmsTemplate; import org.springframework.jms.core.MessageCreator; import org.springframework.stereotype.Component; import com.tiantian.springintejms.service.ProducerService; @Component public class ProducerServiceImpl implements ProducerService { @Autowired private JmsTemplate jmsTemplate; @Autowired @Qualifier("responseQueue") private Destination responseDestination; public void sendMessage(Destination destination, final String message) { System.out.println("---------------生产者发送消息-----------------"); System.out.println("---------------生产者发了一个消息:" + message); jmsTemplate.send(destination, new MessageCreator() { public Message createMessage(Session session) throws JMSException { TextMessage textMessage = session.createTextMessage(message); textMessage.setJMSReplyTo(responseDestination); return textMessage; } }); } }
xml配置文件:
<!-- 用于测试消息回复的 --> <bean id="responseQueue" class="org.apache.activemq.command.ActiveMQQueue"> <constructor-arg> <value>responseQueue</value> </constructor-arg> </bean> <!-- responseQueue对应的监听器 --> <bean id="responseQueueListener" class="com.tiantian.springintejms.listener.ResponseQueueListener"/> <!-- responseQueue对应的监听容器 --> <bean id="responseQueueMessageListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer"> <property name="connectionFactory" ref="connectionFactory"/> <property name="destination" ref="responseQueue"/> <property name="messageListener" ref="responseQueueListener"/> </bean>
ResponseQueueListener的定义以下所示:
public class ResponseQueueListener implements MessageListener { public void onMessage(Message message) { if (message instanceof TextMessage) { TextMessage textMessage = (TextMessage) message; try { System.out.println("接收到发送到responseQueue的一个文本消息,内容是:" + textMessage.getText()); } catch (JMSException e) { e.printStackTrace(); } } } }
生产者发送消息被MessageListenerAdapter处理以后,MessageListenerAdapter把监听器的返回内容封装成一个Message,往原Message经过setJMSReplyTo方法指定的回复目的地发送了一个消息。对于MessageListenerAdapter对应的监听器处理方法返回的是一个null值或者返回类型是void的状况,MessageListenerAdapter是不会自动进行消息的回复的。
(2)经过MessageListenerAdapter的defaultResponseDestination属性来指定。在定义MessageListenerAdapter的时候经过其defaultResponseDestination属性指定其默认的回复目的地是“defaultResponseQueue”,并定义defaultResponseQueue对应的消息监听器和消息监听容器。
<!-- 消息监听适配器 --> <bean id="messageListenerAdapter" class="org.springframework.jms.listener.adapter.MessageListenerAdapter"> <!-- <constructor-arg> <bean class="com.tiantian.springintejms.listener.ConsumerListener"/> </constructor-arg> --> <property name="delegate"> <bean class="com.tiantian.springintejms.listener.ConsumerListener"/> </property> <property name="defaultListenerMethod" value="receiveMessage"/> <property name="defaultResponseDestination" ref="defaultResponseQueue"/> </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> !-- 默认的消息回复队列 --> <bean id="defaultResponseQueue" class="org.apache.activemq.command.ActiveMQQueue"> <constructor-arg> <value>defaultResponseQueue</value> </constructor-arg> </bean> <!-- defaultResponseQueue对应的监听器 --> <bean id="defaultResponseQueueListener" class="com.tiantian.springintejms.listener.DefaultResponseQueueListener"/> <!-- defaultResponseQueue对应的监听容器 --> <bean id="defaultResponseQueueMessageListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer"> <property name="connectionFactory" ref="connectionFactory"/> <property name="destination" ref="defaultResponseQueue"/> <property name="messageListener" ref="defaultResponseQueueListener"/> </bean>
当两种方式都指定了消息的回复目的地的时候使用发送消息的setJMSReplyTo方法指定的目的地将具备较高的优先级,MessageListenerAdapter将只往该方法指定的消息回复目的地发送回复消息。