Spring + ActiveMQ实现生产者消费者模式和发布订阅模式
环境准备
- 安装最新版ActiveMQ
- Jdk1.8
- Spring
创建工程
通过gradle构建项目
引入依赖包
在build.gradle文件中加入以下依赖
//spring
[group: 'org.springframework', name: 'spring-aop', version: springVersion],
[group: 'org.springframework', name: 'spring-core', version: springVersion],
[group: 'org.springframework', name: 'spring-web', version: springVersion],
[group: 'org.springframework', name: 'spring-jms', version: springVersion],
[group: 'org.springframework', name: 'spring-context-support', version: springVersion],
//JMS
[group: 'org.springframework', name: 'spring-jms', version: springVersion],
[group: 'org.apache.xbean', name: 'xbean-spring', version: '4.6'],
[group: 'org.apache.activemq', name: 'activemq-core', version: '5.7.0'],
配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:amq="http://activemq.apache.org/schema/core"
xmlns:jms="http://www.springframework.org/schema/jms"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms-4.0.xsd
http://activemq.apache.org/schema/core
http://activemq.apache.org/schema/core/activemq-core-5.8.0.xsd">
<!-- ActiveMQ 连接工厂 -->
<amq:connectionFactory id="amqConnectionFactory" brokerURL="tcp://localhost" userName="admin" password="admin"/>
<!-- Spring Caching 连接工厂 -->
<!-- Spring用于管理真正的ConnectionFactory的ConnectionFactory -->
<bean id="connectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="amqConnectionFactory"></property>
<!-- Session缓存数量 -->
<property name="sessionCacheSize" value="100"></property>
</bean>
<!-- Spring JmsTemplate的消息生产者 -->
<!-- 定义JmsTemplate的Queue -->
<bean id="jmsQueueTemplate" class="org.springframework.jms.core.JmsTemplate">
<constructor-arg ref="connectionFactory"/>
<!-- 非发布订阅模式 -->
<property name="pubSubDomain" value="false"></property>
</bean>
<!-- 定义JmsTemplate的Topic类型 -->
<bean id="jmsTopicTemplate" class="org.springframework.jms.core.JmsTemplate">
<constructor-arg ref="connectionFactory"/>
<!-- 发布订阅模式 -->
<property name="pubSubDomain" value="true"></property>
</bean>
<!-- Spring JmsTemplate的消息消费者 -->
<!-- 定义Queue监听器 -->
<jms:listener-container destination-type="queue" container-type="default" connection-factory="connectionFactory">
<jms:listener destination="test.queue" ref="queueReceiver1"/>
<jms:listener destination="test.queue" ref="queueReceiver2"/>
</jms:listener-container>
<!-- 定义Topic监听器 -->
<jms:listener-container destination-type="topic" container-type="default" connection-factory="connectionFactory">
<jms:listener destination="test.topic" ref="topicReceiver1"/>
<jms:listener destination="test.topic" ref="topicReceiver2"/>
</jms:listener-container>
<bean id="topicReceiver1" class="listener.topic.topicReceiver1"></bean>
<bean id="topicReceiver2" class="listener.topic.topicReceiver2"></bean>
<bean id="queueReceiver1" class="listener.queue.queueReceiver1"></bean>
<bean id="queueReceiver2" class="listener.queue.queueReceiver2"></bean>
</beans>
目录结构
- api
- QueueActiveApi
- TopicActiveApi
- service
- SendQueueMessage
- SendTopicMessage
- listener
- queue
- topic
RESTful Api接口
QueueActiveApi
package api;
import java.text.MessageFormat;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import service.SendQueueMessage;
@Path("active")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class QueueActiveApi {
private final Logger log = Logger.getLogger(getClass());
private final int counts=10;
@Autowired
private SendQueueMessage sendMessage;
@POST
@Path("/queue")
public Response setSmsActiveQueue() {
log.info("队列模式--开始发送消息");
System.out.println("队列模式--开始发送消息");
for (int i = 1; i < counts; i++) {
String message=MessageFormat.format("我是第{0}条消息", i);
log.info(message);
sendMessage.doSendAction(message);
}
return Response.ok().build();
}
}
TopicActiveApi
package api;
import java.text.MessageFormat;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import service.SendQueueMessage;
import service.SendTopicMessage;
@Path("active")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class TopicActiveApi {
private final Logger log = Logger.getLogger(getClass());
private final int counts=10;
@Autowired
private SendTopicMessage sendMessage;
@POST
@Path("/topic")
public Response setSmsActiveTopic() {
log.info("订阅模式--开始发送消息");
System.out.println("订阅模式--开始发送消息");
for (int i = 1; i < counts; i++) {
String message=MessageFormat.format("我是第{0}条消息", i);
sendMessage.doSendAction(message);
}
return Response.ok().build();
}
}
发送消息
SendQueueMessage
package service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Service;
@Service
public class SendQueueMessage {
@Autowired
@Qualifier("jmsQueueTemplate")
private JmsTemplate jmsQueueTemplate;
public void doSendAction(String message) {
jmsQueueTemplate.convertAndSend("test.queue",message);
}
}
SendTopicMessage
package service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Service;
@Service
public class SendTopicMessage {
@Autowired
@Qualifier("jmsTopicTemplate")
private JmsTemplate jmsTopicTemplate;
public void doSendAction(String message) {
jmsTopicTemplate.convertAndSend("test.topic", message);
}
}
消息监听者
Point-to-Point模式实现两个消费者
queueReceiver1
package listener.queue;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
import org.springframework.stereotype.Component;
@Component
public class queueReceiver1 implements MessageListener{
@Override
public void onMessage(Message message) {
TextMessage tm = (TextMessage) message;
try {
System.out.println("QueueReceiver1接收到消息:"+tm.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
queueReceiver2
package listener.queue;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
import org.springframework.stereotype.Component;
@Component
public class queueReceiver2 implements MessageListener{
@Override
public void onMessage(Message message) {
TextMessage textMessage=(TextMessage) message;
try {
System.out.println("QueueReceiver2接收到消息:"+textMessage.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
Pub-Sub模式实现两个订阅者
topicReceiver1
package listener.topic;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
import org.springframework.stereotype.Component;
@Component
public class topicReceiver1 implements MessageListener{
@Override
public void onMessage(Message message) {
try {
System.out.println("TopicReceiver1接收到消息:"+((TextMessage)message).getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
topicReceiver2
package listener.topic;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
import org.springframework.stereotype.Component;
@Component
public class topicReceiver2 implements MessageListener{
@Override
public void onMessage(Message message) {
try {
System.out.println("TopicReceiver1接收到消息:"+((TextMessage)message).getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
运行结果
- 对于Point-to-Point模式,一条消息只会被一个消费者消费
- 对于Pub-Sub模式,一条消息会被所有订阅者消费