4,源代码
一,导入的包:
二,applicationContext.xml的配置和注意事项:
1,创建一个真正的基于 jsm提供者的联接工厂,采用的是apache-activemq-5.13.0服务器:
<bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616"/>
</bean>
2, 采用ActiveMQ联接池的方案,一次性创建多个连接,当需要时从池中取,这样有利于速率的提高。
<bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory">
<property name="connectionFactory" ref="targetConnectionFactory" />
<property name="maxConnections" value="100" />
</bean>
3,创建spring联接工厂,从链接工厂中取得
<bean id="singleConnectionFactory"
class="org.springframework.jms.connection.SingleConnectionFactory">
<property name="targetConnectionFactory" ref="pooledConnectionFactory" />
</bean>
4,配置jmsTemplate 它简化了JMS的使用因为它处理创建和发送或接收消息时资源同步发布。
注意:
在使用jmsTemplate 发送消息是不要将send()写成sendAndReceive(),
否则会造成回复的信息,进入到相同队列,后面设置的回复队列会不起作用
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="singleConnectionFactory" />
</bean>
5,创建两个队列,用来存发送和回复的消息。
<!-- 以下用于存放生产者发送的信息 -->
<bean id="sendQueueDestination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg>
<value>sendQueue</value>
</constructor-arg>
</bean>
<!-- 以下用于存放消费者回复的信息 -->
<bean id="replyQueueDestination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg>
<value>replyQueue</value>
</constructor-arg>
</bean>
6,配置监听器和监听器运行的容器
注意:1,监听器里属性名不要乱写,只能写容器有的对应,否则会注值不进
2,一个容器只能对应一个监听器
<!-- 配置 sessionAware的临听器 可以回复的-->
<bean id="consumerMessageListener2" class="com.yc.jms5.ConsumerMessageListener2" >
</bean>
<bean id="consumerMessageListener3" class="com.yc.jms5.ConsumerMessageListener3">
</bean>
<!-- 配置 consumerMessageListener2的容器 -->
<bean id="sessionAwareListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer" >
<property name="connectionFactory" ref="singleConnectionFactory" />
<property name="destination" ref="sendQueueDestination" />
<property name="messageListener" ref="consumerMessageListener2" />
</bean>
<!-- 配置 consumerMessageListener3的容器 注意下面的属性名不要乱写,只能写容器对应的,否则会注值不进-->
<bean id="jmsContainer3" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="singleConnectionFactory" />
<property name="destination" ref="replyQueueDestination" />
<property name="messageListener" ref="consumerMessageListener3" />
</bean>
三,监听器的类型和注意事项:
在Spring整合JMS的应用中我们在定义消息监听器的时候一共可以定义三种类型的消息监听器,分别是MessageListener、SessionAwareMessageListener和MessageListenerAdapter。下面就分别来介绍一下这几种类型的区别。
1,MessageListener:
MessageListener是最原始的消息监听器,它是JMS规范中定义的一个接口。其中定义了一个用于处理接收到的消息的onMessage方法,该方法只接收一个Message参数。我们前面在讲配置消费者的时候用的消息监听器就是MessageListener。
2,SessionAwareMessageListener:
SessionAwareMessageListener是Spring为我们提供的,它不是标准的JMS MessageListener。MessageListener的设计只是纯粹用来接收消息的,假如我们在使用MessageListener处理接收到的消息时我们需要发送一个消息通知对方我们已经收到这个消息了,那么这个时候我们就需要在代码里面去重新获取一个Connection或Session。SessionAwareMessageListener的设计就是为了方便我们在接收到消息后发送一个回复的消息,它同样为我们提供了一个处理接收到的消息的onMessage方法,但是这个方法可以同时接收两个参数,一个是表示当前接收到的消息Message,另一个就是可以用来发送消息的Session对象。
3,MessageListenerAdapter:
MessageListenerAdapter类实现了MessageListener接口和SessionAwareMessageListener接口,它的主要作用是将接收到的消息进行类型转换,然后通过反射的形式把它交给一个普通的Java类进行处理。
MessageListenerAdapter会把接收到的消息做如下转换:
TextMessage转换为String对象;
BytesMessage转换为byte数组;
MapMessage转换为Map对象;
ObjectMessage转换为对应的Serializable对象。
既然前面说了MessageListenerAdapter会把接收到的消息做一个类型转换,然后利用反射把它交给真正的目标处理器——一个普通的Java类进行处理(如果真正的目标处理器是一个MessageListener或者是一个SessionAwareMessageListener,那么Spring将直接使用接收到的Message对象作为参数调用它们的onMessage方法,而不会再利用反射去进行调用),那么我们在定义一个MessageListenerAdapter的时候就需要为它指定这样一个目标类。这个目标类我们可以通过MessageListenerAdapter的构造方法参数指定。
详细网址:http://haohaoxuexi.iteye.com/blog/1893676
四:源代码
1,发送消息接口:
package com.yc.jms5;
public interface PersonService {
public void sendMessage(String message);
}
2,发送消息实现类:
package com.yc.jms5;
import javax.annotation.Resource;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Service;
@Service("personServiceImpl2")
public class PersonServiceImpl2 implements PersonService {
private Destination destination; //用于存发送信息的队列
private JmsTemplate jsmTemplate; //jms操作模板
private Destination replyDestination; //用于存回复信息的队列,
@Override
public void sendMessage(final String message) {
System.out.println("生产者->发送消息" + message);
//回调
//jsmTemplate.sendAndReceive(messageCreator)注意不要使用这个,这个会造成回复的信息,进入到相同队列,后面设置的回复队列会不起作用
jsmTemplate.send(destination, new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
Message msg =session.createTextMessage(message);
//设置回复信息的目的地
msg.setJMSReplyTo(replyDestination);
// 设置发送的信息类型 为非持久化信息
msg.setJMSDeliveryMode(DeliveryMode.NON_PERSISTENT);
return msg;
}
});
}
@Resource(name="sendQueueDestination")
public void setDestination(Destination destination) {
this.destination = destination;
}
@Resource(name="jmsTemplate")
public void setJsmTemplate(JmsTemplate jsmTemplate) {
this.jsmTemplate = jsmTemplate;
}
@Resource(name="replyQueueDestination")
public void setReplyDestination(Destination replyDestination) {
this.replyDestination = replyDestination;
}
}
3,发送队列监听器:
package com.yc.jms5;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.springframework.jms.listener.SessionAwareMessageListener;
public class ConsumerMessageListener2 implements SessionAwareMessageListener<TextMessage> {
public void onMessage(TextMessage message, Session session) throws JMSException {
System.out.println("ConsumerMessageListener2接收到的消息:"+ message.getText());
//通过session 创建 producer对象,再回送信息
//从message中取出信息回送的目的地,以便创建生产者.
MessageProducer producer=session.createProducer(message.getJMSReplyTo());
//创建一条
Message textMessage=session.createTextMessage( "生产者发过来的信息已经处理完毕,game over..." );
//调用发送
producer.send(textMessage);
}
}
4,回复队列监听器:
package com.yc.jms5;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
public class ConsumerMessageListener3 implements MessageListener {
@Override
public void onMessage(Message message) {
if(message instanceof TextMessage){
TextMessage text=(TextMessage) message;
System.out.println("ConsumerMessageListerner3服务器接收到的回复信息:"+ text);
}
}
}
5,测试类:
package com.yc.jms5;
import org.apache.xbean.spring.context.ClassPathXmlApplicationContext;
import org.springframework.context.ApplicationContext;
public class test {
public static void main(String[] args) {
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
PersonService ps=(PersonService) ac.getBean("personServiceImpl2");
ps.sendMessage("我是生产者2生产的消息: hello world");
}
}
6,xml配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 启用注解解析器 -->
<context:annotation-config />
<!-- 因为采用了混合解析方式( 有一部分配置在xml中,有一部分在java类中,所以要让spring的注解解析器去扫描包 -->
<context:component-scan base-package="com.yc.jms5" />
<!-- 启用aspectj的注解方式的代理 -->
<aop:aspectj-autoproxy />
<!-- 创建一个真正的基于 jsm提供者的联接工厂 -->
<bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616"/>
</bean>
<!-- ActiveMQ联接池的方案 -->
<bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory">
<property name="connectionFactory" ref="targetConnectionFactory" />
<property name="maxConnections" value="100" />
</bean>
<!-- 创建spring联接工厂 -->
<bean id="singleConnectionFactory"
class="org.springframework.jms.connection.SingleConnectionFactory">
<property name="targetConnectionFactory" ref="pooledConnectionFactory" />
</bean>
<!-- 配置jmsTemplate 它简化了JMS的使用因为它处理创建和发送或接收消息时资源同步发布。-->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="singleConnectionFactory" />
</bean>
<!-- 以下用于存放生产者发送的信息 -->
<bean id="sendQueueDestination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg>
<value>sendQueue</value>
</constructor-arg>
</bean>
<!-- 以下用于存放消费者回复的信息 -->
<bean id="replyQueueDestination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg>
<value>replyQueue</value>
</constructor-arg>
</bean>
<!-- 配置 sessionAware的临听器 可以回复的-->
<bean id="consumerMessageListener2" class="com.yc.jms5.ConsumerMessageListener2" >
</bean>
<bean id="consumerMessageListener3" class="com.yc.jms5.ConsumerMessageListener3">
</bean>
<!-- 配置 consumerMessageListener2的容器 -->
<bean id="sessionAwareListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer" >
<property name="connectionFactory" ref="singleConnectionFactory" />
<property name="destination" ref="sendQueueDestination" />
<property name="messageListener" ref="consumerMessageListener2" />
</bean>
<!-- 配置 consumerMessageListener3的容器 注意下面的属性名不要乱写,只能写容器对应的,否则会注值不进-->
<bean id="jmsContainer3" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="singleConnectionFactory" />
<property name="destination" ref="replyQueueDestination" />
<property name="messageListener" ref="consumerMessageListener3" />
</bean>
</beans>