Spring整合ActiveMQ
maven引入依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>4.3.23.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-pool</artifactId>
<version>5.15.9</version>
</dependency>
发送队列消息
<?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: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-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<context:component-scan base-package="cn.fg.jsm.producer" />
<!-- activemq 连接池 -->
<bean id="connectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory">
<property name="connectionFactory">
<bean class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://192.168.1.3:61616" /> <!-- activemq 服务器地址 -->
</bean>
</property>
<!-- <property name="maxConnections" value="10" /> --> <!-- 最大连接数,默认1 -->
<!-- <property name="maximumActiveSessionPerConnection" value="100" /> --> <!-- 每个连接的最大会话数,默认500 -->
<!-- <property name="idleTimeout" value="60000" /> --> <!-- 创建的连接的空闲超时值(毫秒),默认30秒 -->
</bean>
<!-- 创建 queue -->
<bean id="queueDestination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="queue03"/>
</bean>
<!-- 创建 topic -->
<bean id="topicDestination" class="org.apache.activemq.command.ActiveMQTopic">
<constructor-arg value="topic03"/>
</bean>
<!-- 创建jmsTemplate -->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="defaultDestination" ref="queueDestination"/> <!-- 默认目的地,队列或主题 -->
<!-- spring 消息转换器,可以使用convertAndSend发送或接收消息,默认为SimpleMessageConverter,存在多个转换器,使用搜百度 -->
<property name="messageConverter">
<bean class="org.springframework.jms.support.converter.SimpleMessageConverter"></bean>
</property>
</bean>
<!-- 配置jms事务管理器 -->
<bean id="transactionManager" class="org.springframework.jms.connection.JmsTransactionManager">
<property name="connectionFactory" ref="connectionFactory"/>
</bean>
<!-- 注解方式配置事物 -->
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
package cn.fg.jsm.producer;
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.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Component;
@Component
public class ProducerQueue {
@Autowired
@Qualifier("jmsTemplate4Queue03") //当有多个jmsTemplate时,指定使用哪一个
private JmsTemplate jmsTemplate; //这个jmsTemplate有一个默认目的地Queue03
//发送消息
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-jms.xml");
ProducerQueue producerQueue = ctx.getBean(ProducerQueue.class);
//使用消息转换器发送消息
producerQueue.jmsTemplate.convertAndSend("这是一个convertAndSend消息:" + System.currentTimeMillis());
//可以发送给其他目的地,convertAndSend有很多重载方法
producerQueue.jmsTemplate.convertAndSend("queue01", "这是一个queue01消息:" + System.currentTimeMillis());
//使用session发送消息
producerQueue.jmsTemplate.send(new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
//原生写法创建一个TextMessage
TextMessage textMessage = session.createTextMessage("这是一个TextMessage消息:" + System.currentTimeMillis());
return textMessage;
}
});
System.out.println("消息发送完毕");
}
}
package cn.fg.jsm.producer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Component
public class ProducerQueue {
@Autowired
private JmsTemplate jmsTemplate;
@Transactional() //开启事务
public void send(){
//使用spring转换器发送消息
jmsTemplate.convertAndSend("这是一个convertAndSend消息:" + System.currentTimeMillis());
//测试异常,异常后事务回滚,消息不会发送到mq服务器
//int i = 1 / 0;
//使用普通发送消息
/*jmsTemplate.send(new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
TextMessage textMessage = session.createTextMessage(String.valueOf(System.currentTimeMillis()));
return textMessage;
}
});*/
System.out.println("消息发送完毕");
}
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-jms.xml");
ProducerQueue producer = ctx.getBean(ProducerQueue.class);
producer.send(); //调用生产者发送消息
}
}
接收队列消息
这里我们使用监听容器接收消息
<?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:context="http://www.springframework.org/schema/context"
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-4.0.xsd">
<context:component-scan base-package="cn.fg.consumer" />
<!-- activemq 连接池 -->
<bean id="connectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory">
<property name="connectionFactory">
<bean class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://192.168.1.3:61616" /> <!-- activemq 服务器地址 -->
</bean>
</property>
<!-- <property name="maxConnections" value="10" /> --> <!-- 最大连接数,默认1 -->
<!-- <property name="maximumActiveSessionPerConnection" value="100" /> --> <!-- 每个连接的最大会话数,默认500 -->
<!-- <property name="idleTimeout" value="60000" /> --> <!-- 创建的连接的空闲超时值(毫秒),默认30秒 -->
</bean>
<!-- 接收消息的 queue -->
<bean id="queueDestination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="queue03"/>
</bean>
<!-- 接收消息的 topic -->
<bean id="topicDestination" class="org.apache.activemq.command.ActiveMQTopic">
<constructor-arg value="topic03"/>
</bean>
<!-- 消息监听容器 -->
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="destination" ref="queueDestination" /> <!-- 监听的目的地,队列或主题 -->
<!-- 指定具体的监听器,spring提供的监听器实现类有多个 -->
<!-- queueMessageListener是我自己定义的实现类 -->
<!-- QueueMessageListener类已经加了@Component注解,所以这里可以不用单独定义一个bean了 -->
<property name="messageListener" ref="queueMessageListener" />
</bean>
</beans>
package cn.fg.consumer;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
//监听器,这里我们用来监听queue03
@Component
public class QueueMessageListener implements MessageListener {
@Override
public void onMessage(Message message) {
if(message != null && message instanceof TextMessage){
TextMessage textMessage = (TextMessage) message;
try {
System.out.println(textMessage.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
//启动消费者
public static void main(String[] args) {
new ClassPathXmlApplicationContext("spring-jms.xml");
}
}
发送主题消息
<!-- 创建 topic -->
<bean id="topicDestination" class="org.apache.activemq.command.ActiveMQTopic">
<constructor-arg value="topic03"/>
</bean>
<!-- 创建jmsTemplate -->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="defaultDestination" ref="topicDestination"/> <!-- 改为主题 -->
<!-- messageConverter 默认值就是SimpleMessageConverter 可以不用写 -->
<!-- <property name="messageConverter">
<bean class="org.springframework.jms.support.converter.SimpleMessageConverter"></bean>
</property> -->
</bean>
package cn.fg.jsm.producer;
import org.apache.activemq.command.ActiveMQTopic;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Component
public class ProducerTopic {
@Autowired
private JmsTemplate jmsTemplate;
@Autowired
private ActiveMQTopic activeMQTopic; //使用xml中定义的主题
@Transactional()
public void send(){
//发送主题
jmsTemplate.convertAndSend(activeMQTopic, "topic03:"+ System.currentTimeMillis());
//也可以不用再xml定义 new一个主题发送
//jmsTemplate.convertAndSend(new ActiveMQTopic("topic04"), "topic04:"+ System.currentTimeMillis());
System.out.println("消息发送完毕");
}
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-jms.xml");
ProducerTopic producer = ctx.getBean(ProducerTopic.class);
producer.send(); //调用生产者发送消息
}
}
接收主题消息
<!-- 接收消息的 queue -->
<bean id="queueDestination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="queue03"/>
</bean>
<!-- 队列消息监听容器 -->
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="destination" ref="queueDestination" /> <!-- 监听的目的地,队列或主题 -->
<!-- 指定具体的监听器,spring提供的监听器实现类有多个 -->
<!-- queueMessageListener是我自己定义的实现类 -->
<!-- QueueMessageListener类已经加了@Component注解,所以这里可以不用单独定义一个bean了 -->
<property name="messageListener" ref="queueMessageListener" />
</bean>
<!-- 接收消息的 topic -->
<bean id="topicDestination" class="org.apache.activemq.command.ActiveMQTopic">
<constructor-arg value="topic03"/>
</bean>
<!-- 可以在定义一个监听主题的监听器 -->
<bean id="topicMessageListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="destination" ref="topicDestination" /> <!-- 设置需要监听的主题 -->
<property name="messageListener" ref="topicMessageListener" />
</bean>
package cn.fg.consumer;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
//监听器,这里我们用来监听topic03
@Component
public class TopicMessageListener implements MessageListener {
@Override
public void onMessage(Message message) {
if(message != null && message instanceof TextMessage){
TextMessage textMessage = (TextMessage) message;
try {
System.out.println(textMessage.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new ClassPathXmlApplicationContext("spring-jms.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:context="http://www.springframework.org/schema/context"
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-4.0.xsd">
<context:component-scan base-package="cn.fg.consumer" />
<!-- 连接池 -->
<bean id="connectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory">
<property name="connectionFactory">
<bean class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://192.168.1.3:61616" />
<property name="clientID" value="004" /> <!-- 设置clientID,持久主题订阅必须的 -->
</bean>
</property>
</bean>
<!-- topic -->
<bean id="topicDestination" class="org.apache.activemq.command.ActiveMQTopic">
<constructor-arg value="topic04"/>
</bean>
<!-- 监听容器 -->
<bean id="topicMessageListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="destination" ref="topicDestination" /> <!-- 设置需要监听的主题 -->
<property name="messageListener" ref="durableTopicMessageListener" /> <!-- 监听实现类 -->
<!-- <property name="subscriptionDurable" value="true"/> --> <!-- 开启持久订阅,默认false -->
<!-- 设置持久订阅名称,如果名称不为null,则subscriptionDurable自动设置为true -->
<property name="durableSubscriptionName" value="mydurableSubscription" />
</bean>
</beans>
package cn.fg.consumer;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
//监听实现类
@Component
public class DurableTopicMessageListener implements MessageListener {
@Override
public void onMessage(Message message) {
if(message != null && message instanceof TextMessage){
TextMessage textMessage = (TextMessage) message;
try {
System.out.println(textMessage.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
//启动消费者
public static void main(String[] args) {
new ClassPathXmlApplicationContext("spring-durable-topic.xml");
}
}
消息监听适配器MessageListenerAdapter
MessageListenerAdapter在监听到消息的同时,还可以使用当前的session回复消息
TextMessage textMessage = session.createTextMessage("这是一个消息" + System.currentTimeMillis());
textMessage.setJMSReplyTo(new ActiveMQQueue("queue-replyto")); //生产者发送消息时设置了回复地址(队列)
messageProducer.send(textMessage);
package cn.fg.consumer;
import org.springframework.stereotype.Component;
//自定义的消费者监听类,不实现任何接口
@Component
public class ConsumerListener {
/**
* 用来接收消息的方法,参数为生产者发送的消息内容
* MessageListenerAdapter会把接收到的消息做如下转换:
* TextMessage转换为String
* BytesMessage转换为byte[]
* MapMessage转换为Map
* ObjectMessage转换为对应的Serializable
*/
public void handleMessage(String message) {
System.out.println("handleMessage:" + message);
}
/**
* 如果方法有返回值,则会以该返回值作为消息内容进行回复
* 返回值类型同样遵循上述转换规则
* @return
*/
public String receiveMessage(String message) {
System.out.println("receiveMessage:" + message);
return "bbbbbbbbbbbbbbbbb";
}
}
<!-- 接收消息的 queue -->
<bean id="queueDestination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="queue03"/>
</bean>
<!-- 消息监听适配器 -->
<bean id="messageListenerAdapter" class="org.springframework.jms.listener.adapter.MessageListenerAdapter">
<property name="delegate" ref="consumerListener" /> <!-- 监听委托类,需要自己创建,consumerListener已经@Component -->
<property name="defaultListenerMethod" value="receiveMessage"/> <!-- 监听方法名,需要在委托类中创建该方法,默认为 handleMessage-->
<!-- 默认回复目的地,如果生产者未设置JMSReplyTo,则以该值作为回复地址 -->
<!-- <property name="defaultResponseDestination" ref="responseDestination"/> -->
</bean>
<!-- 消息监听容器 -->
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="destination" ref="queueDestination" /> <!-- 监听哪个队列 -->
<property name="messageListener" ref="messageListenerAdapter" /> <!-- 监听器,这里我们注入messageListenerAdapter -->
</bean>
执行情况:调用生产者发送消息,消费者监听到消息后,同时又向queue-replyto回复了消息