再rabbitMQ中,有两个重要的组件。exchange(交换机),queue(队列)。交换机用于路由消息,简单来说就是接收客户端传递的消息
,转发
到queue中。队列做的事情就是存储消息
。
但消息并不会一只存储在队列中。当存在一下三种情况,消息就会死掉
当遇到死掉的消息时,我们通常会将这些死信
转发到新的交换机中,这个交换机就叫做死信交换机
,而配合死信交换机存储信息的队列,叫做死信队列
死信队列在构建延迟队列时,有巨大作用
。比如用户购票订单,30min不支付就过期。在rabbitMQ中可以这样实现
exchange-queue
中整个流程中,出现了三方。在编写代码时,我们可以分三个大类,分别是producer
,consumer1
,consumer2
。其消息传递顺序如下
producer
-> normal_exchangeconsumer1
consumer2
我们可以在编写consumer1
的时候,完成exchange和queue的创建与绑定
<dependency>
<groupId>com.rabbitmqgroupId>
<artifactId>amqp-clientartifactId>
<version>5.9.0version>
dependency>
rabbitMQ整体的编写流程如下
因此,我们可以先创建工具类,帮我们获取channel,以此减少开发代码量
public class MQUtils {
public static Channel getChannel() throws Exception {
// 创建工厂链接
ConnectionFactory factory = new ConnectionFactory();
// 设置工厂
factory.setHost("your_ip");
factory.setUsername("your_username");
factory.setPassword("your_password");
factory.setVirtualHost("/"); // 基本都是/
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
return channel;
}
}
public class Consumer1 {
static String EXCHANGE_NAME = "normal_exchange";
static String QUEUE_NAME = "normal_queue";
static String DEAD_EXCHANGE_NAME = "dead_exchange";
static String DEAD_QUEUE_NAME = "dead_queue";
public static void main(String[] args) throws Exception{
Channel channel = MQUtils.getChannel();
// 普通交换机
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT, false, true, null);
// 普通队列
// 配置死信交换机参数
HashMap<String, Object> map = new HashMap<>();
// 配置normal_queue连接的dead_exchange
map.put("x-dead-letter-exchange", DEAD_EXCHANGE_NAME);
// 设置normal_queue的消息过期时间
map.put("x-message-ttl", 10000);
// 设置路由到死信交换机的路由key: lisi
map.put("x-dead-letter-routing-key", "lisi");
// map.put("x-max-length", 6); // 设置队列最大长度
channel.queueDeclare(QUEUE_NAME, false, false, true, map);
// 绑定普通交换机和普通队列
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "zhangsan");
// 死信交换机
channel.exchangeDeclare(DEAD_EXCHANGE_NAME, BuiltinExchangeType.DIRECT, false, true, false, null);
// 死信队列
channel.queueDeclare(DEAD_QUEUE_NAME, false, false, true, null);
// 绑定死信交换机和死信队列
channel.queueBind(DEAD_QUEUE_NAME, DEAD_EXCHANGE_NAME, "lisi");
// 监听
channel.basicConsume(QUEUE_NAME, false, (consumerTag, message) -> {
System.out.println("监听普通队列: " + new String(message.getBody()));
}, consumerTag -> {});
}
}
public class Consumer2{
static String DEAD_QUEUE_NAME = "dead_queue";
public static void main(String[] args) throws Exception{
Channel channel = MQUtils.getChannel();
// 监听
channel.basicConsume(DEAD_QUEUE_NAME, true, (consumerTag, message) -> {
System.out.println("监听死信队列: " + new String(message.getBody()));
}, consumerTag -> {});
}
}
public class Producer {
static String EXCHANGE_NAME = "normal_exchange";
public static void main(String[] args) throws Exception{
Channel channel = MQUtils.getChannel();
for (int i = 0; i < 10; i++) {
String msg = i + "";
channel.basicPublish(EXCHANGE_NAME, "zhangsan",
null,
msg.getBytes());
}
}
}
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-amqpartifactId>
<version>2.3.9.RELEASEversion>
dependency>
package com.xhf.mq.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;
@Configuration
public class TTLConfig {
/*-----交换机名称-----*/
private static final String EXCHANGE_NAME = "X";
private static final String DEAD_EXCHANGE_NAME = "Y";
/*-----队列名称-----*/
private static final String QUEUE_NAME1 = "QA";
private static final String QUEUE_NAME2 = "QB";
private static final String DEAD_QUEUE_NAME = "QD";
// 注册交换机
@Bean("xExchange")
public DirectExchange xExchange() {
return ExchangeBuilder.directExchange(EXCHANGE_NAME)
.autoDelete()
.build();
// return new DirectExchange(EXCHANGE_NAME);
}
// 注册死信交换机
@Bean("deadExchange")
public DirectExchange deadExchange() {
return ExchangeBuilder.directExchange(DEAD_EXCHANGE_NAME)
.autoDelete()
.build();
}
// 注册队列QA
@Bean("queueA")
public Queue queueA() {
return QueueBuilder
.nonDurable(QUEUE_NAME1)
.withArgument("x-message-ttl", 10000)
.withArgument("x-dead-letter-exchange", DEAD_EXCHANGE_NAME)
.withArgument("x-dead-letter-routing-key", "YD")
.build();
}
// 注册队列QB
@Bean("queueB")
public Queue queueB() {
return QueueBuilder
.nonDurable(QUEUE_NAME2)
.withArgument("x-message-ttl", 40000)
.withArgument("x-dead-letter-exchange", DEAD_EXCHANGE_NAME)
.withArgument("x-dead-letter-routing-key", "YD")
.build();
}
// 注册队列QD
@Bean("queueD")
public Queue queueD() {
return QueueBuilder
.nonDurable(DEAD_QUEUE_NAME)
.build();
}
// 绑定普通交换机, 队列
@Bean
public Binding queueABindingX(@Qualifier("queueA") Queue queueA, @Qualifier("xExchange") Exchange xExchange) {
return BindingBuilder.bind(queueA).to(xExchange).with("XA").and(null);
}
@Bean
public Binding queueBBindingX(@Qualifier("queueB") Queue queueB, @Qualifier("xExchange") Exchange xExchange) {
return BindingBuilder.bind(queueB).to(xExchange).with("XB").and(null);
}
// 绑定死信交换机, 队列
@Bean
public Binding queueDBindingY(@Qualifier("queueD") Queue queueD, @Qualifier("deadExchange") Exchange deadExchange) {
return BindingBuilder.bind(queueD).to(deadExchange).with("YD").and(null);
}
}
@GetMapping("/sendToQA")
public void sendToQA() {
// 向X交换机发送消息, 消息通过"XA"路由到队列
rabbitTemplate.convertAndSend("X", "XA", "hello".getBytes());
}
@Component
public class Customer {
@RabbitListener(queues = "QD")
public void customer(Message message, Channel channel) {
byte[] body = message.getBody();
System.out.println(new String(body));
}
}