持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第7天,点击查看活动详情
1 保证消息一定送达到Exchange
在这一步是靠Confirm机制来确保的
可以通过Confirm效果保证消息一定送达到Exchange,官方提供了三种方式:
- 单独发布消息,发布消息并同步等待确认
- 批量发布消息,发布一批消息,等待足额人整批消息
- 异步处理发布和确认消息,代理异步确认已发布的消息,只需在客户机上注册一个回调,就可以得到确认消息的通知。
我们选择了对于效率影响最低的异步回调的效果
它会在发消息之前指定一个回调函数,无论消息发送成功或失败都能得到一个结果
//4. 开启confirms
channel.confirmSelect();
//5. 设置confirms的异步回调
channel.addConfirmListener(new ConfirmListener() {
@Override
public void handleAck(long deliveryTag, boolean multiple) throws IOException {
System.out.println("消息成功的发送到Exchange!");
}
@Override
public void handleNack(long deliveryTag, boolean multiple) throws IOException {
System.out.println("消息没有发送到Exchange,尝试重试,或者保存到数据库做其他补偿操作!");
}
});
2 保证消息可以路由到Queue
在这一步,是依靠Return机制实现的, 当Exchange上的消息没有送达到Queue时,则执行return回调函数。
在发送消息时,将basicPublish方法参数中的mandatory设置为true,即可开启Return机制,当消息没有路由到队列中时,就会执行return回调
//6. 设置Return回调,确认消息是否路由到了Queue
channel.addReturnListener(new ReturnListener() {
@Override
public void handleReturn(int replyCode, String replyText, String exchange, String routingKey, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消息没有路由到指定队列,做其他的补偿措施!!");
}
});
3 保证Queue可以持久化消息
DeliveryMode
设置消息持久化
DeliveryMode设置为2代表持久化,如果设置为1,就代表不会持久化。
// 设置消息持久化
AMQP.BasicProperties props = new AMQP.BasicProperties()
.builder()
.deliveryMode(2)
.build();
// 发布消息
channel.basicPublish("","confirms",true,props,message.getBytes());
4 保证消费者可以正常消费消息
只有关闭自动ACK,开启手动ACK的时候才能保证消息正常消费。
当业务逻辑执行完毕的时候执行手动ACK即可,也就是WorkQueue模式
5 SpringBoot实现上述操作
5.1 Confirm
编写配置文件开启Confirm机制
spring:
rabbitmq:
publisher-confirm-type: correlated # 新版本
publisher-confirms: true # 老版本
在发送消息时,配置RabbitTemplate
@Test
public void publishWithConfirms() throws IOException {
rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
if(ack){
System.out.println("消息已经送达到交换机!!");
}else{
System.out.println("消息没有送达到Exchange,需要做一些补偿操作!!retry!!!");
}
}
});
rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE,"big.black.dog","message");
System.out.println("消息发送成功");
System.in.read();
}
5.2 Return
编写配置文件开启Return机制
spring:
rabbitmq:
publisher-returns: true # 开启Return机制
在发送消息时,配置RabbitTemplate
@Test
public void publishWithReturn() throws IOException {
// 新版本用 setReturnsCallback ,老版本用setReturnCallback
rabbitTemplate.setReturnsCallback(new RabbitTemplate.ReturnsCallback() {
@Override
public void returnedMessage(ReturnedMessage returned) {
String msg = new String(returned.getMessage().getBody());
System.out.println("消息:" + msg + "路由队列失败!!做补救操作!!");
}
});
rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE,"big.black.dog","message");
System.out.println("消息发送成功");
System.in.read();
}
5.3 消息持久化
@Test
public void publishWithBasicProperties() throws IOException {
rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE, "big.black.dog", "message", new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message message) throws AmqpException {
// 设置消息的持久化!
message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
return message;
}
});
System.out.println("消息发送成功");
}