死信交换机:
个人理解死信交换机就是存储一些过期的消息而产生的,本质上跟普通的交换机没有任何区别。当然了普通交换机和死信交换机的应用场景是不同的,首先我们配置死信交换机,本次采用spring-boot进行测试:
导入pom:
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.6.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
配置yml
spring:
rabbitmq:
host: 192.168.44.23
port: 5672
username: admin
password: 123456
virtual-host: /
publisher-confirms: true
publisher-returns: true
编写rabbitMQ的配置类:
@Configuration
public class RabbitMQConfig {
//交换机
@Bean("bootExchange")
public Exchange bootExchange() {
return ExchangeBuilder.topicExchange("boot-topic_exchange").durable(true).build();
}
//队列
@Bean("bootQueue")
public Queue bootQueue() {
return QueueBuilder.durable("boot-topic_queues").build();
}
//队列
@Bean("bootQueues")
public Queue bootQueues() {
return QueueBuilder.durable("boot-topic_queues2").build();
}
//交换机和队列进行绑定
@Bean
public Binding bindingQueuesExchange(@Qualifier("bootQueue") Queue queue, @Qualifier("bootExchange") Exchange exchange) {
BindingBuilder.bind(queue).to(exchange).with("boot213.#").noargs();
return BindingBuilder.bind(queue).to(exchange).with("boot.#").noargs();
}
//---------------------------死信交换机配置---------------------------------
//创建死信交换器
@Bean
public DirectExchange demo01DeadExchange() {
return new DirectExchange("dead_exchange", true, false);
}
//死信队列
@Bean
public Queue demo01DeadQueue() {
return new Queue("dead_queue", true, false, false);
}
//创建队列
@Bean
public Queue demo01Queue() {
Map<String, Object> params = new HashMap<>(8);
// 设置消息过期时长5秒
params.put("x-message-ttl", 5000);
// 设置死信交换器
params.put("x-dead-letter-exchange", "dead_exchange");
// 设置死信交换器路由键 -- 失败之后转发到那个死信路由
params.put("x-dead-letter-routing-key", "boot.*");
return new Queue("boot_queues", true, false, false, params);
}
//死信交换器与死信队列绑定
@Bean
public Binding demo01DeadBinding() {
return BindingBuilder.bind(demo01DeadQueue()).to(demo01DeadExchange()).with("boot.*");
}
//给交换机和队列添加路由key
@Bean
public Binding demo01Binding(@Qualifier("bootExchange") Exchange exchange) {
return BindingBuilder.bind(demo01Queue()).to(exchange).with("boot.*").noargs();
}
}
@Configuration
public class ProducerRabbitConfig {
@Resource
private ConnectionFactory connectionFactory;
/**
* 多例的RabbitTemplate
* @return
*/
@Bean
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public RabbitTemplate scopeRabbitTemplate(){
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMandatory(true);
return rabbitTemplate;
}
}
@Service
public class RabbitSender {
@Resource
private ApplicationContext applicationContext;
/**
* 每次获取新的RabbitTemplate
* @return
*/
public RabbitTemplate getScopeRabbitTemplate(){
RabbitTemplate scopeRabbitTemplate = (RabbitTemplate) applicationContext.getBean("scopeRabbitTemplate");
return scopeRabbitTemplate;
}
}
发送消息:
/**
* 回退模式: 当消息发送给Exchange后,Exchange路由到Queue失败是 才会执行 ReturnCallBack +TTL
* 步骤:
* 1. 开启回退模式:publisher-returns="true"
* 2. 设置ReturnCallBack
* 3. 设置Exchange处理消息的模式:
* 1. 如果消息没有路由到Queue,则丢弃消息(默认)
* 2. 如果消息没有路由到Queue,返回给消息发送方ReturnCallBack
*/
@RequestMapping("testReturnMQ")
public void testReturn() {
RabbitTemplate rabbitsTemplate = rabbitSender.getScopeRabbitTemplate();
//设置交换机处理失败消息的模式
rabbitsTemplate.setMandatory(true);
//2.设置ReturnCallBack
rabbitsTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
/**
* @param message 消息对象
* @param replyCode 错误码
* @param replyText 错误信息
* @param exchange 交换机
* @param routingKey 路由键
*/
@Override
public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
System.out.println("return 执行了....");
System.out.println(message);
System.out.println(replyCode);
System.out.println(replyText);
System.out.println(exchange);
System.out.println(routingKey);
}
});
//3. 发送消息 TTL -消息在三秒后未被接收,自动清理,转为死消息
rabbitsTemplate.convertAndSend("boot-topic_exchange", "boot.231", "message confirm....", new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message message) throws AmqpException {
message.getMessageProperties().setExpiration("3000");//
return message;
}
});
}
延迟队列:
延迟队列就是在我可以在30秒中之后去消费该消息,运用场景为:下单后30分钟未支付,将该商品放入库存中。实现方案在rabbitMQ中未提供,这个时候我们可以使用TTL+死信队列来实现,TTL就是设置消息的存活时间或者过期时间,在该时间内未被消费则进入死信队列中,死信队列中接收到该消息进行消费,从而达到延迟队列的效果。上面代码有具体实现可以测试一下。