这里探讨一下使用RabbitTemplate进行发布者确认
不讲废话直接上代码
第一步 :配置yml,主要是rabbitmq部分
讲解:
- publisher-returns:发布成功失败以后的处理,默认false发布失败的时候会将消息丢弃,设置publisher-returns为true时消息成功则会向发布者发送成功,失败时不会将消息丢弃,而是返回给发布者,发布者根据需求处理
- publisher-confirm-type: 开启发布确认模式,具体有三个值,具体的可以去百度
spring:
application:
name: rabbitmq-provider
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
virtual-host: /
publisher-returns: true #设置publisher-returns消息成功则会向发布者发送成功,失败时不会将消息丢弃,而是返回给发布者,发布者根据需求处理
publisher-confirm-type: correlated #开启发布确认模式,具体有三个值,具体的可以去百度
第二步 :创建交换器和队列并绑定这里使用的amqpAdmin去做这件事
amqpAdmin.declareExchange(new DirectExchange("testExchange"));
amqpAdmin.declareQueue(new Queue("testQueue", true));
amqpAdmin.declareBinding(new Binding("testQueue", Binding.DestinationType.QUEUE, "testExchange", "testQueue", new HashMap<>()));
第三步 :(重要)发布者确认的关键代码
1.同步确认:每一次发送完消息都要等待rabbitmq确认完毕以后才会执行后面的代码。注意这个相当影响性能
// 记录开始的时间
long begin=System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
boolean b = Boolean.TRUE.equals(template.invoke(operations -> {
template.convertAndSend("testQueue", "发布的消息");
return template.waitForConfirms(1000);
}));
if(b) {
System.out.println("发布成功");
} else {
System.out.println("发布失败");
}
}
// 记录结束的时间
long end=System.currentTimeMillis();
return (end-begin)+"ms";
2. 异步确认:每一次发送完消息不等待rabbitmq响应,直接执行后面的代码,当rabbitmq响应成功或者失败时会通过ack告诉发布者
long begin=System.currentTimeMillis();
template.setConfirmCallback((CorrelationData correlationData, boolean ack, String cause) -> {
if (ack) {
System.out.println("发布成功");
} else {
System.out.println("发布失败");
}
});
for (int i = 0; i < 1000; i++) {
template.convertAndSend("testQueue", "发布的消息");
}
long end=System.currentTimeMillis();
System.out.println((end-begin)+"ms");
return (end-begin)+"ms";
对比两种方式发1000条消息的耗时
同步大于4044ms,异步大约292ms两者相差一百多倍的速度,所以非必要不要使用同步的方式。
完整的逻辑代码
package com.example.demo.controller;
import jakarta.annotation.Resource;
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.connection.CorrelationData;
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.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.util.HashMap;
@RestController()
@RequestMapping("/rabbimq")
public class RabbitmController {
@Resource
RabbitTemplate template;
@Resource
AmqpAdmin amqpAdmin;
@Autowired
public void RabbitmController() {
amqpAdmin.declareExchange(new DirectExchange("testExchange"));
amqpAdmin.declareQueue(new Queue("testQueue", true));
amqpAdmin.declareBinding(new Binding("testQueue", Binding.DestinationType.QUEUE, "testExchange", "testQueue", new HashMap<>()));
System.out.println("使用构造方法");
}
@GetMapping("/affair/asynchronous")
public String affair_sync(@RequestParam("msg") String msg) throws IOException {
long begin=System.currentTimeMillis();
template.setConfirmCallback((CorrelationData correlationData, boolean ack, String cause) -> {
if (ack) {
System.out.println("发布成功");
} else {
System.out.println("发布失败");
}
});
for (int i = 0; i < 1000; i++) {
template.convertAndSend("testQueue", "发布的消息");
}
long end=System.currentTimeMillis();
System.out.println((end-begin)+"ms");
return (end-begin)+"ms";
}
@GetMapping("/affair/affair")
public String affair(){
long begin=System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
boolean b = Boolean.TRUE.equals(template.invoke(operations -> {
template.convertAndSend("testQueue", "发布的消息");
return template.waitForConfirms(1000);
}));
if(b) {
System.out.println("发布成功");
} else {
System.out.println("发布失败");
}
}
long end=System.currentTimeMillis();
return (end-begin)+"ms";
}
}