目录
1.消息中间件说明
参考: 别纠结了,教你如何做 ------消息中间件选型分析
2.ActiveMQ下载安装
地址:http://activemq.apache.org/
下载得到zip文件,解压后,进如bin\win64,打开activemq.bat,开始启动。
浏览器输入http://localhost:8161/admin/,用户名密码admin/admin登录。
3.添加maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- activeMQ依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<!-- jms连接池,springboot2.1.*+使用 -->
<dependency>
<groupId>org.messaginghub</groupId>
<artifactId>pooled-jms</artifactId>
</dependency>
<!-- jms连接池,springboot2.0.*及以下使用 -->
<!--
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-pool</artifactId>
</dependency>
-->
注意,springboot2.0.*及以下和springboot2.1.*+使用jms连接池的依赖是不同的,引用不当会抛出异常: spring boot2.0整合activeMQ,配置连接池,启动项目报错,JmsMessagingTemplate无法注入。
4.springboot配置
# ActiveMQ地址
spring.activemq.broker-url=tcp://localhost:61616
# 配置用户名和密码
spring.activemq.user=admin
spring.activemq.password=admin
# 是否使用发布订阅模式,默认是为false,即是用的是点对点的模式
spring.jms.pub-sub-domain=true
# 默认目的地址
spring.jms.template.default-destination=activemq.default.destination
# 是否启用连接池
spring.activemq.pool.enabled=true
# 连接池最大连接数配置
spring.activemq.pool.max-connections=50
# 信任所有包
spring.activemq.packages.trust-all=true
5.消息生产代码
package com.zyf.springTech.activemq;
import java.io.Serializable;
public class MessageRequestDto implements Serializable {
private static final long serialVersionUID = -8532307584713967506L;
// 业务id
private String id;
// 业务数据
private String data;
// setters and getters...
}
package com.zyf.springTech.activemq;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.TextMessage;
import org.apache.activemq.command.ActiveMQQueue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Service;
//消息生产者
@Service
public class MessageProducer {
// 生产者地址
private static final String DESTINATION_PRODUCER = "MY_DESTINATION_PRODUCER";
// 生产者接收回复地址
private static final String DESTINATION_PRODUCER_REPLY = "DESTINATION_PRODUCER_REPLY";
// 消费者地址
private static final String DESTINATION_CONSUMER = "MY_DESTINATION_CONSUMER";
@Autowired
private JmsTemplate jmsTemplate;
// 发送消息
public void send(MessageRequestDto req) {
jmsTemplate.send(DESTINATION_CONSUMER, session -> {
// 设置业务数据(可以是json)
TextMessage message = session.createTextMessage(req.getData());
// 设置消息关联id,将请求和应答消息关联起来
message.setJMSCorrelationID(req.getId());
// 设置消息回复的目的地
ActiveMQQueue replyTo = new ActiveMQQueue(DESTINATION_PRODUCER_REPLY);
message.setJMSReplyTo(replyTo);
return message;
});
}
// 接收应答
@JmsListener(destination = DESTINATION_PRODUCER_REPLY)
public void onResponse(TextMessage message) throws JMSException {
System.out.println("生产方接收到应答,关联id:" + message.getJMSCorrelationID());
System.out.println("生产方接收到应答,消息内容:" + message.getText());
}
}
实际使用中,是不是可以将业务数据放到Message的text中,按照json规范组织字符串?
处理结束后消费方发送一条应答,而发送消息和应到之间通过JMSCorrelationID关联。
6.消息消费代码
package com.zyf.springTech.activemq;
import javax.jms.JMSException;
import javax.jms.Queue;
import javax.jms.TextMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Service;
//消息消费者
@Service
public class MessageConsumer {
// 消费者地址
private static final String DESTINATION_CONSUMER = "MY_DESTINATION_CONSUMER";
@Autowired
private JmsTemplate jmsTemplate;
// 接收消息
@JmsListener(destination = DESTINATION_CONSUMER)
public void onRequest(TextMessage message) throws JMSException {
System.out.println("消费方接收到关联id:" + message.getJMSCorrelationID());
System.out.println("消费方接收到消息内容:" + message.getText());
reply(message);
}
// 应答
private void reply(TextMessage receivemessage) throws JMSException {
// 获取消息回复目的地和关联id,向回复目的地发送回复消息
Queue replyTo = (Queue) receivemessage.getJMSReplyTo();
jmsTemplate.send(replyTo.getQueueName(), session -> {
// 设置业务数据(可以是json)
TextMessage message = session.createTextMessage("你好,zhangsan,来信已经收到");
// 设置消息关联id,将请求和应答消息关联起来
message.setJMSCorrelationID(receivemessage.getJMSCorrelationID());
return message;
});
}
}
使用JmsTemplate模板操作消息,发送消息,@JmsListener订阅消息。
代码参考:
7.测试
package com.zyf.springTech.activemq;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
// ActiveMQ 消息控制器
@Controller
@RequestMapping("/activemq")
public class MessageController {
@Autowired
private MessageProducer messageProducer;
@RequestMapping("/send")
public String sendMessage() {
MessageRequestDto req = new MessageRequestDto();
req.setId("a000001");
req.setData("你好,我是zhangsan");
messageProducer.send(req);
return "activemq/send";
}
}
浏览器访问:http://localhost:8081/activemq/send
日志输出:
消费方接收到关联id:a000001
消费方接收到消息内容:你好,我是zhangsan
生产方接收到应答,关联id:a000001
生产方接收到应答,消息内容:你好,zhangsan,来信已经收到
8.观察activemq控制台
观察topics。
【简要描述】
Number Of Consumers 消费者 “这个是消费者端的消费者数量”
Number Of Pending Messages 等待消费的消息 “这个是当前未出队列的数量。可以理解为总接收数-总出队列数”
Messages Enqueued 进入队列的消息 “进入队列的总数量,包括出队列的。 这个数量只增不减”
Messages Dequeued 出了队列的消息 “可以理解为是消费这消费掉的数量”
参考:Active MQ Web管理界面功能介绍
8.1 消息生产者和消费者系统启动前
8.1 消息生产者和消费者系统启动后
发现两个topic都有消费者,说明被订阅了。
8.1 消息生产者和消费者完成一次消息发送、消息消费、消息发送(例子中的应答)后
每个topic都发送了一次消息,且各消息都被消费了一次。
github:https://github.com/zhangyangfei/SpringBootLearn.git中的springTech工程。