SpringBoot整个RabbitMQ详细~
搭建环境
1、安装RabbitMQ,我是用的是Docker方式安装的,大家根据个人习惯自行安装哈
docker run -d -p 5672:5672 -p 15672:15672 --name rabbitmq -e RABBITMQ_DEFAULT_USER=qbb -e RABBITMQ_DEFAULT_PASS=qbb rabbitmq:3.8-management
SpringBoot整合RabbitMQ
Producer生产者端代码
1、创建一个maven工程
2、导入相关的依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.qbb</groupId>
<artifactId>springboot-rabbitmq</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.7</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
</project>
3、编写application.yml配置文件
server:
port: 9001
spring:
application:
name: springboot-rabbitmq
rabbitmq:
host: # 你MQ的地址
port: 5672
username: admin
password: admin
virtual-host: /
4、主启动类
package com.qbb.rabbitmq;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit)
* @version 1.0
* @date 2022-07-28 21:33
* @Description:
*/
@SpringBootApplication
public class SpringBootRabbitMQ {
public static void main(String[] args) {
SpringApplication.run(SpringBootRabbitMQ.class, args);
}
}
5、业务逻辑
(1)我们创建一个RabbitMQConfig的配置类,帮助我们来创建交换机、队列以及绑定关系
package com.qbb.rabbitmq.config;
import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit)
* @version 1.0
* @date 2022-07-28 21:34
* @Description:
*/
@Configuration
public class RabbitMQConfig {
/**
* 交换机名称
*/
public static final String TOPIC_EXCHANGE_NAME = "qiu_topic_exchange";
/**
* 队列名称
*/
public static final String QUEUE_NAME = "qiu_queue";
/**
* 创建交换机
*
* @return
*/
@Bean("qiuExchange")
public Exchange createExchange() {
return ExchangeBuilder.topicExchange(TOPIC_EXCHANGE_NAME).durable(true).build();
}
/**
* 创建队列
*
* @return
*/
@Bean("qiuQueue")
public Queue createQueue() {
return QueueBuilder.durable(QUEUE_NAME).build();
}
/**
* 绑定交换机和队列
*
* @param qiuExchange
* @param qiuQueue
* @return
*/
@Bean
public Binding binding(@Qualifier("qiuExchange") Exchange qiuExchange, @Qualifier("qiuQueue") Queue qiuQueue) {
return BindingBuilder.bind(qiuQueue).to(qiuExchange).with("qiu.#").noargs();
}
}
(2)编写Producer发送消息的测试代码
package com.qbb.rabbitmq;
import com.qbb.rabbitmq.config.RabbitMQConfig;
import org.junit.jupiter.api.Test;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
/**
* @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit)
* @version 1.0
* @date 2022-07-28 21:56
* @Description:
*/
@SpringBootTest
public class ProducerTest {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void testSendMsg(){
rabbitTemplate.convertAndSend(RabbitMQConfig.TOPIC_EXCHANGE_NAME,
"qiu.haha", "等我完成目标就来找你~");
}
}
Consumer消费者端代码
1、创建一个maven工程
2、导入相关的依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.qbb</groupId>
<artifactId>springboot-rabbitmq-consumer</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.7</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
</project>
3、编写application.yml配置文件
server:
port: 9002
spring:
application:
name: springboot-rabbitmq
rabbitmq:
host:
port: 5672
username: admin
password: admin
virtual-host: /
4、主启动类
package com.qbb.rabbitmq;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit)
* @version 1.0
* @date 2022-07-28 22:09
* @Description:
*/
@SpringBootApplication
public class SpringBootRabbitMQConsumer {
public static void main(String[] args) {
SpringApplication.run(SpringBootRabbitMQConsumer.class, args);
}
}
5、业务逻辑
(1)创建一个MQListener监听器,用于监听队列消费消息
package com.qbb.rabbitmq.listener;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
/**
* @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit)
* @version 1.0
* @date 2022-07-28 22:10
* @Description:
*/
@Component
public class RabbitMQListener {
/**
* 监听队列
*
* @param message
*/
@RabbitListener(queues = "qiu_queue")
public void msgConsumer(Message message) {
System.out.println("message = " + message);
}
}
(2)启动主程序测试一下
RabbitMQ高级特性
1、消息可靠性投递confirm确认模式和return回退模式
- 修改yml配置文件
spring:
application:
name: springboot-rabbitmq
rabbitmq:
host:
port: 5672
username: admin
password: admin
virtual-host: /
# 是否触发回调方法
# NONE值是禁用发布确认模式,是默认值
# CORRELATED值是发布消息成功到交换器后会触发回调方法
# SIMPLE值经测试有两种效果:
# 其一效果和CORRELATED值一样会触发回调方法
# 其二在发布消息成功后使用rabbitTemplate
# 调用waitForConfirms或waitForConfirmsOrDie方法等待broker节点返回发送结果,根据返回结果来判定下一步的逻辑,
# 要注意的点是waitForConfirmsOrDie方法如果返回false则会关闭channel,则接下来无法发送消息到broker;
publisher-confirm-type: correlated
publisher-returns: true
listener:
simple:
# 开启手动确定
acknowledge-mode: manual
- 编写测试代码
package com.qbb.rabbitmq;
import com.qbb.rabbitmq.config.RabbitMQConfig;
import org.junit.jupiter.api.Test;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
/**
* @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit)
* @version 1.0
* @date 2022-07-28 21:56
* @Description:
*/
@SpringBootTest
public class ProducerTest {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void testSendMsg(){
/**
* false:RabbitMQ会把消息直接丢弃
* true:RabbitMQ会调用Basic.Return命令将消息返回给生产者
*/
rabbitTemplate.setMandatory(true);
//设置ReturnsCallback
rabbitTemplate.setReturnsCallback( returnedMessage -> {
//消息对象
Message message = returnedMessage.getMessage();
//错误码
int replyCode = returnedMessage.getReplyCode();
//错误信息
String replyText = returnedMessage.getReplyText();
//交换机
String exchange = returnedMessage.getExchange();
//路由key
String routingKey = returnedMessage.getRoutingKey();
System.out.println("消息从交换机到队列失败,详细信息如下:");
System.out.println("消息对象:"+message);
System.out.println("错误码:"+replyCode);
System.out.println("错误信息:"+replyText);
System.out.println("交换机:"+exchange);
System.out.println("路由key:"+routingKey);
});
//设置ConfirmCallback
rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
/**
* @param correlationData 相关配置信息
* @param ack 交换机是否成功收到消息
* @param cause 错误信息
*/
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
if (ack){
System.out.println("成功发送消息到交换机");
}else {
System.out.println("消息发送到交换机失败");
System.out.println("失败原因:"+cause);
}
}
});
// 错误的示例,大家自行修改
rabbitTemplate.convertAndSend(RabbitMQConfig.TOPIC_EXCHANGE_NAME,
"qiu.haha", "等我完成目标就来找你~");
}
}
2、Consumer端手动ACK
RabbitMQ提供了三种确认方式:
- 自动确认:acknowledge="none"
- 手动确认:acknowledge="manual"
- 根据异常情况确认:acknowledge="auto" (不推荐)
修改配置文件
listener:
type: simple
simple:
#采用手动应答
acknowledge-mode: manual
prefetch: 1 #限制每次发送一条数据。
添加一个ACKListener监听器
package com.qbb.rabbitmq.listener;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.io.IOException;
/**
* @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit)
* @version 1.0
* @date 2022-07-29 21:32
* @Description:
*/
@Component
public class AckListener {
@RabbitListener(queues = {"akc-queue"})
public void testQueue(Message message, Channel channel) throws IOException {
System.out.println("ack-queue消费:" + new String(message.getBody()));
/*
listener:
type: simple
simple:
#采用手动应答
acknowledge-mode: manual
prefetch: 1 #限制每次发送一条数据。
*/
// 采用手动ack,一条条的消费
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
/**
* 参数一:DeliveryTag
* 参数二:是否接收多个消息
* 参数三:是否重回队列,如果为true消息会重新回到queue, broker会重新发送该消息给消费端
*/
//channel.basicNack(message.getMessageProperties().getDeliveryTag(),true,true);
}
}
测试
3、Consumer端限流
修改配置文件
#采用手动应答
acknowledge-mode: manual
prefetch: 1 #限制每次消费N条数据。
4、TTL
- 设置队列的过期时间
- x-message-ttl,单位:ms(毫秒),这样的话进入队列的所有消息都遵循这个过期时间。
- 设置单个消息的过期时间(expiretion)
- expiration,单位:ms(毫秒),这样的话只有这条消息有过期时间。这里的消息过期了,如果这条消息是在头部,才会丢弃
5、死信队列
- 消息成为死信的三种情况
- 消息超过了队列的最大长度(max-length)
- Consumer端basicNAck|basicReject,消费端拒收,并且requeue=false不重新入队
- 消息过期
6、延迟队列(RabbitMQ没有这个实现)
- 但是我们可以通过TTL+死信队列解决
7、日志与监控
http://ip:15672/
直接访问web图形化界面,用命令也可以查看,但是个人感觉没有图形化界面友好!!!
8、保证消息的幂等性
- 使用乐观锁的方式解决
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!