目录
3.创建一个实现abbitTemplate.ConfirmCallback接口的实现类
1.概述:
参考(16条消息) RabbitMQ消息100%可靠性投递的解决方案实现(一)_eluanshi12的博客-CSDN博客_rabbitmq可靠性投递
可靠性消息:
在使用RabbitMQ时,作为消息发送方希望杜绝消息丢失或者投递失败的场景。RabbitMQ为我们提供了两种方式用来控制消息的投递可靠性。
confirm模式:
生产者发送消息到交换机时,使用这种模式
return模式:
交换机转发给queue时,使用这种模式
2.confirm模式代码实现:
1.加入依赖:
<!--rabbitmq起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2.在配置文件中开启confirm模式 :
spring:
rabbitmq:
port: 5672
host: localhost
username: guest
password: guest
virtual-host: /
#开启confirms这个模式
#springboot2.2.0.RELEASE支持这个
#publisher-confirm-type: correlated
publisher-confirms: true
3.创建一个实现abbitTemplate.ConfirmCallback接口的实现类
package com.example.confirm;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Component;
@Component
public class MyConfirmCallBack implements RabbitTemplate.ConfirmCallback {
/**
* 回调方法,发送消息后都会调用该方法
* @param correlationData 数据
* @param ack true发送成功 ,false发送失败
* @param cause 如果是失败,那么返回这个失败原因的字符串。如果成功 原因就是null
*/
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
if(ack){
//模拟在这里减100
System.out.println("发送成功,减100成功");
}else{
System.out.println("发送失败,失败原因是:"+cause);
}
}
}
4.在配置类或者启动类创建交换机,队列,绑定队列和交换机
package com.example;
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.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class Day47RabbitMqApplication {
public static void main(String[] args) {
SpringApplication.run(Day47RabbitMqApplication.class, args);
}
//创建交换机
@Bean
public DirectExchange directExchange(){
return new DirectExchange("exchange_test6");
}
//创建队列
@Bean
public Queue queue(){
return new Queue("queue_test6");
}
//创建绑定
@Bean
public Binding binding(){
return BindingBuilder.bind(queue()).to(directExchange()).with("test6.insert");
}
}
5.测试 :
测试消息发送到交换机
package com.example.controller;
import com.example.confirm.MyConfirmCallBack;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/testsend")
public class TestSendController {
@Autowired
private RabbitTemplate rabbitTemplate;
@Autowired
//或者用这个
//private MyConfirmCallBack myConfirmCallBack;
private RabbitTemplate.ConfirmCallback confirmCallback;
@GetMapping ("/send1")
public String send1(){
//设置回调函数
rabbitTemplate.setConfirmCallback(confirmCallback);
//发送消息
//rabbitTemplate.convertAndSend("exchange_test6","test6.insert","消息本身");
//测试一个错误,没有这个交换机
rabbitTemplate.convertAndSend("exchange_test88","test6.insert","消息本身");
return "ok";
}
}
我们测试一个错误,把交换机名称改一下,就会发现在控制台会打印错误详情。
至此我们就可以知道消息发送到交换机是否中间出现了问题,这个时候就会多一个问题,我们发现修改路由key之后,回调函授会显示消息发送成功。
所以我们需要处理交换机到路由的这个过程,消息是否转发成功。return模式。
3.return模式
完成上面的依赖以及配置后
在配置文件中开始return模式
spring:
rabbitmq:
port: 5672
host: localhost
username: guest
password: guest
virtual-host: /
#开启confirms这个模式
#springboot2.2.0.RELEASE支持这个
#publisher-confirm-type: correlated
publisher-confirms: true
#开启return模式
publisher-returns: true
然后创建一个实现类(2.2版本)实现RabbitTemplate.ReturnCallback接口:
package com.example.confirm;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Component;
@Component
public class MyReturnCallBack implements RabbitTemplate.ReturnCallback {
/**
*
* 交换机转发消息到队列时调用 , 如果成功的时候就不调用该方法了,只有转发失败的时候才调用
* @param message 消息内容本身
* @param replyCode 响应状态码
* @param replyText 响应内容
* @param exchange 交换机
* @param routingKey routingKey
*/
@Override
public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
//获取到消息本身
System.out.println(new String(message.getBody()));
//message.getMessageProperties()可以获取到其他的别的信息
//状态码
System.out.println(replyCode);
System.out.println(replyText);
//exchange
System.out.println(exchange);
//routingKey
System.out.println(routingKey);
}
}
测试一个错误,把交换机改正确,routingKey写错
package com.example.controller;
import com.example.confirm.MyConfirmCallBack;
import com.example.confirm.MyReturnCallBack;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/testsend")
public class TestSendController {
@Autowired
private RabbitTemplate rabbitTemplate;
@Autowired
//或者用这个
//private MyConfirmCallBack myConfirmCallBack;
private RabbitTemplate.ConfirmCallback confirmCallback;
@Autowired
//private MyReturnCallBack myReturnCallBack;
//或者用这个
private RabbitTemplate.ReturnCallback returnsCallback;
@GetMapping ("/send1")
public String send1(){
//设置confirm回调函数
rabbitTemplate.setConfirmCallback(confirmCallback);
//设置return回调函数
rabbitTemplate.setReturnCallback(returnsCallback);
//发送消息
//rabbitTemplate.convertAndSend("exchange_test6","test6.insert","消息本身");
//测试一个错误,把交换机改正确,routingKey写错
rabbitTemplate.convertAndSend("exchange_test6","test6.insertxxx","消息本身");
return "ok";
}
}
小结:一般我们使用confirm模式就可以了,在消息发送到交换机时机去使用。一般交换机转发消息到队列不会丢失消息。