本文整合MQ交换机类型为Direct,下面是各类交换机类型的大概介绍
Direct Exchange(直连交换机):消息会传送给绑定键与消息的路由键完全匹配的那个队列。
Fanout Exchange(扇形交换机):扇形交换机将消息路由给绑定到自身的所有消息队列,也就是说路由键在扇形交换机里没有作用,故消息队列绑定扇形交换机时,路由键可为空。这个模式类似于广播。
Topic Exchange(主题交换机):消息路由键—发送到主题交换机的消息所携带的路由键(routing_key)不能随意命名——它必须是一个用点号分隔的词列表。当中的词可以是任何单词,不过一般都会指定一些跟消息有关的特征作为这些单词。
*
(星号) 能够替代一个单词。
#
(井号) 能够替代零个或多个单词。
Headers Exchange(头交换机):头交换机类似与主题交换机,但是却和主题交换机有着很大的不同。主题交换机使用路由键来进行消息的路由,而头交换机使用消息属性来进行消息的分发,通过判断消息头的值能否与指定的绑定相匹配来确立路由规则。
整合springboot
<!--RabbitMQ 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
yaml文件配置
spring:
rabbitmq:
host: 服务器地址
port: 5672
username: admin
password: 123
创建对应的config配置
package com.example.myselfmq.config;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author Maple
* @description: TODO
* @date 2022/8/12 20:31
*/
@Configuration
public class DirectConfig {
// 交换机名称
public static final String DIRECT_EXCHANGE_NAME = "direct_exchange";
// 队列名称
public static final String DIRECT_QUEUEQ_NAME = "direct_queue";
// RoutingKey
public static final String DIRECT_ROUTING_KEY = "key1";
// 声明交换机
@Bean
public DirectExchange directExchange(){
return new DirectExchange(DIRECT_EXCHANGE_NAME);
}
// 声明队列
@Bean
public Queue directQueue(){
return new Queue(DIRECT_QUEUEQ_NAME);
}
// 绑定交换机和队列
@Bean
public Binding queueBindingExchange(@Qualifier("directExchange")DirectExchange directExchange,@Qualifier("directQueue")Queue directQueue){
return BindingBuilder.bind(directQueue).to(directExchange).with(DIRECT_ROUTING_KEY);
}
}
创建消息生产者
package com.example.myselfmq.Controller;
import com.example.myselfmq.config.DirectConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Maple
* @description: TODO
* @date 2022/8/12 20:40
*/
@Slf4j
@RestController
@RequestMapping("producer")
public class ProducerController {
@Autowired
private RabbitTemplate rabbitTemplate;
// 发消息
@GetMapping("/sendMessage/{message}")
public void sendMessage(@PathVariable String message){
rabbitTemplate.convertAndSend(DirectConfig.DIRECT_EXCHANGE_NAME,DirectConfig.DIRECT_ROUTING_KEY, message);
log.info("成功发送消息:{}",message);
}
}
创建消费者
package com.example.myselfmq.consumer;
import com.example.myselfmq.config.DirectConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
/**
* @author Maple
* @description: TODO
* @date 2022/8/12 20:48
*/
@Slf4j
@Component
public class ConsumerReceiver {
// 消费消息
@RabbitListener(queues = DirectConfig.DIRECT_QUEUEQ_NAME)
public void receiveConfirmMessage(Message message){
log.info("接收到的队列消息为:{}",new String(message.getBody()));
}
}
测试发送消息是否成功消费
消息被成功消费
设置消息TTL以及配置死信队列
package com.example.myselfmq.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;
import java.util.HashMap;
import java.util.Map;
/**
* @author Maple
* @description: TODO
* @date 2022/8/12 20:31
* @email 576235959@qq.com
*/
@Configuration
public class DirectConfig {
// 交换机名称
public static final String DIRECT_EXCHANGE_NAME = "direct_exchange";
// 队列名称
public static final String DIRECT_QUEUEQ_NAME = "direct_queue";
// 队列b
public static final String DIRECT_QUEUEQ_B_NAME = "direct_b_queue";
// RoutingKey
public static final String DIRECT_ROUTING_KEY = "key1";
// 队列bRoutingKey
public static final String DIRECT_B_ROUTING_KEY = "key2";
// 死信交换机
public static final String DEAD_LETTER_EXCHANGE = "dead_exchange";
// 死信队列
public static final String DEAD_LETTER_QUEUE = "dead_queue";
// 死信RoutingKey
public static final String DEAD_LETTER_ROUTING_KEY = "dead_queue";
// 声明交换机
@Bean
public DirectExchange directExchange(){
return new DirectExchange(DIRECT_EXCHANGE_NAME);
}
// 声明队列
@Bean
public Queue directQueue(){
Map<String,Object> arguments = new HashMap<>();
// 设置死信交换机
arguments.put("x-dead-letter-exchange",DEAD_LETTER_EXCHANGE);
// 设置死信RoutingKey
arguments.put("x-dead-letter-routing-key",DEAD_LETTER_ROUTING_KEY);
// 设置TTL
arguments.put("x-message-ttl",10000);
// 业务队列绑定死信交换机
return QueueBuilder.durable(DIRECT_QUEUEQ_NAME).withArguments(arguments).build();
}
@Bean
public Queue directBQueue(){
Map<String,Object> arguments = new HashMap<>();
// 设置死信交换机
arguments.put("x-dead-letter-exchange",DEAD_LETTER_EXCHANGE);
// 设置死信RoutingKey
arguments.put("x-dead-letter-routing-key",DEAD_LETTER_ROUTING_KEY);
// 设置TTL
arguments.put("x-message-ttl",40000);
// 业务队列绑定死信交换机
return QueueBuilder.durable(DIRECT_QUEUEQ_B_NAME).withArguments(arguments).build();
}
// 绑定交换机和队列
@Bean
public Binding queueBindingExchange(@Qualifier("directExchange")DirectExchange directExchange,
@Qualifier("directQueue")Queue directQueue){
return BindingBuilder.bind(directQueue).to(directExchange).with(DIRECT_ROUTING_KEY);
}
@Bean
public Binding queueBBindingExchange(@Qualifier("directExchange")DirectExchange directExchange,
@Qualifier("directBQueue")Queue directBQueue){
return BindingBuilder.bind(directBQueue).to(directExchange).with(DIRECT_B_ROUTING_KEY);
}
// 声明死信交换机
@Bean
public DirectExchange deadExchange(){
return new DirectExchange(DEAD_LETTER_EXCHANGE);
}
// 声明死信队列
@Bean
public Queue deadQueue(){
return new Queue(DEAD_LETTER_QUEUE);
}
// 绑定死信交换机和队列
@Bean
public Binding deadBindingExchange(@Qualifier("deadExchange")DirectExchange deadExchange,
@Qualifier("deadQueue")Queue deadQueue){
return BindingBuilder.bind(deadQueue).to(deadExchange).with(DEAD_LETTER_ROUTING_KEY);
}
}
配置死信消费者监听
package com.example.myselfmq.consumer;
import com.example.myselfmq.config.DirectConfig;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.Date;
/**
* @author Maple
* @description: TODO
* @date 2022/8/12 21:37
* @email 576235959@qq.com
* 死信消费者
*/
@Component
@Slf4j
public class DeadLetterReceiver {
@RabbitListener(queues = DirectConfig.DEAD_LETTER_QUEUE)
public void receiveD(Message message, Channel channel) throws IOException {
String msg = new String(message.getBody());
log.info("当前时间:{},收到死信队列信息{}", new Date(), msg);
}
}
注释消费者监听
修改生产者发送消息代码测试消息过期是否会进入死信队列
@GetMapping("/sendMessage/{message}")
public void sendMessage(@PathVariable String message){
rabbitTemplate.convertAndSend(DirectConfig.DIRECT_EXCHANGE_NAME,DirectConfig.DIRECT_ROUTING_KEY, "消息来自ttl为10s的队列:"+message);
rabbitTemplate.convertAndSend(DirectConfig.DIRECT_EXCHANGE_NAME,DirectConfig.DIRECT_B_ROUTING_KEY, "消息来自ttl为40s的队列:"+message);
log.info("成功发送消息:{}",message);
}
结果:
在等待10s和40s后,消息先后进入死信队列消费
代码优化,不写死ttl改为手动添加
注释config中b队列的ttl属性
修改生产者代码
// 发消息
@GetMapping("/sendMessage/{message}/{ttlTime}")
public void sendMessage(@PathVariable String message,@PathVariable String ttlTime){
rabbitTemplate.convertAndSend(DirectConfig.DIRECT_EXCHANGE_NAME,DirectConfig.DIRECT_ROUTING_KEY, "消息来自ttl为10s的队列:"+message);
rabbitTemplate.convertAndSend(DirectConfig.DIRECT_EXCHANGE_NAME,DirectConfig.DIRECT_B_ROUTING_KEY,
"消息来自ttl为"+ttlTime+"s的队列:"+message, correlationData ->{
correlationData.getMessageProperties().setExpiration(ttlTime);
return correlationData;
});
log.info("成功发送消息:{}",message);
}
将ttl改为参数获取,然后在生产者这边设置队列的ttl属性.
结果: