Release confirmation springboot version
configuration file
It needs to be added in the configuration file
spring.rabbitmq.publisher-confirm-type=correlated
- NONE
Disable publish confirmation mode, which is the default
- CORRELATED
The callback method will be triggered after the message is successfully published to the exchange
- SIMPLE
After testing, there are two effects. One effect is the same as the corelated value, which will trigger the callback method,
Second, after publishing the message successfully, use rabbitTemplate to call waitForConfirms or waitForConfirmsOrDie methods
Wait for the broker node to return the sending result, and determine the logic of the next step according to the returned result. Note:
If the waitForConfirmsOrDie method returns false, the channel will be closed, and messages cannot be sent to the broker next
//Configuration class publishing confirmation @Configuration public class ConfirmConfig { //Switch public static final String CONFIRM_EXCHANGE_NAME = "confirm_exchange"; //queue public static final String CONFIRM_QUEUE = "confirm_queue"; //RoutingKey public static final String CONFIRM_ROUTING_KEY = "confirm_routing_key"; //Claim switch @Bean public DirectExchange confirmExchange(){ return new DirectExchange(CONFIRM_EXCHANGE_NAME); } //Declaration queue @Bean public Queue confirmQueue(){ return QueueBuilder.durable(CONFIRM_QUEUE).build(); } //binding @Bean public Binding queueBindingExchange(@Qualifier("confirmExchange")DirectExchange confirmExchange, @Qualifier("confirmQueue")Queue confirmQueue){ return BindingBuilder.bind(confirmQueue).to(confirmExchange).with(CONFIRM_ROUTING_KEY); } }
Message producer
@Slf4j @RestController @RequestMapping("/confirm") public class ProducerController { @Autowired RabbitTemplate rabbitTemplate; //Send a message @GetMapping("/sendMessage/{message}") public void sendMessage(@PathVariable String message){ CorrelationData correlationData = new CorrelationData("1"); rabbitTemplate.convertAndSend(ConfirmConfig.CONFIRM_EXCHANGE_NAME,ConfirmConfig.CONFIRM_ROUTING_KEY,message,correlationData); log.info("Message content sent:{}",message); //Change routingkey to make him wrong CorrelationData correlationData2 = new CorrelationData("2"); rabbitTemplate.convertAndSend(ConfirmConfig.CONFIRM_EXCHANGE_NAME,ConfirmConfig.CONFIRM_ROUTING_KEY+"2",message,correlationData2); log.info("Message content sent:{}",message); } }
Callback interface
@Component @Slf4j public class MyCallBack implements RabbitTemplate.ConfirmCallback{ @Autowired private RabbitTemplate rabbitTemplate; @PostConstruct public void init(){ //injection rabbitTemplate.setConfirmCallback(this); } /** * Switch confirmation callback method * 1.The messaging switch received a callback * 1.1 CorrelationData The ID and related information of the callback message are saved * 1.2 The switch receives the message ack=true * 1.3 cause - null * 2. Message sending switch accepts failed callback * 2.1 CorrelationData The ID and related information of the callback message are saved * 2.2 The switch receives the message ack = false * 2.3 cause - Reasons for failure */ @Override public void confirm(CorrelationData correlationData, boolean ack, String cause) { String id = correlationData != null ? correlationData.getId() : ""; if (ack){ log.info("I got it id Is:{}News of",id); }else { log.info("The switch has not received id: {}Message due to reason:{}",id,cause); } } }
Message consumer
@Slf4j @Component public class Consumer { @RabbitListener(queues = ConfirmConfig.CONFIRM_QUEUE) public void receiveConfirmMessage(Message message){ String msg = new String(message.getBody()); log.info("Received queue confirm.queue Message:{}",msg); } }
Result analysis
Two messages were sent. The RoutingKey of the first message was "key1" and the RoutingKey of the second message was "key2". Both messages were successfully received by the switch and the confirmation callback of the switch was also received. However, the consumer only received one message because the RoutingKey of the second message was inconsistent with the BindingKey of the queue, and no other queue could receive this message, All second messages are discarded directly.
Fallback message
The queue cannot receive messages, routingKey error, and the queue disappears
When only the producer confirmation mechanism is enabled, the switch will directly send a confirmation message to the message producer after receiving the message. If it is found that the message is not routable, the message will be directly discarded. At this time, the producer does not know the event that the message is discarded.
Add spring. Rabbitmq. Publisher returns = true to the configuration class
Message producer code
@Slf4j @RestController @RequestMapping("/confirm") public class ProducerController { @Autowired RabbitTemplate rabbitTemplate; //Send a message @GetMapping("/sendMessage/{message}") public void sendMessage(@PathVariable String message){ CorrelationData correlationData = new CorrelationData("1"); rabbitTemplate.convertAndSend(ConfirmConfig.CONFIRM_EXCHANGE_NAME,ConfirmConfig.CONFIRM_ROUTING_KEY,message,correlationData); log.info("Message content sent:{}",message); CorrelationData correlationData2 = new CorrelationData("2"); rabbitTemplate.convertAndSend(ConfirmConfig.CONFIRM_EXCHANGE_NAME+"123",ConfirmConfig.CONFIRM_ROUTING_KEY,message,correlationData2); log.info("Message content sent:{}",message); } }
Callback interface
@Component @Slf4j public class MyCallBack implements RabbitTemplate.ConfirmCallback,RabbitTemplate.ReturnsCallback { @Autowired private RabbitTemplate rabbitTemplate; @PostConstruct public void init(){ //injection rabbitTemplate.setConfirmCallback(this); rabbitTemplate.setReturnsCallback(this); } /** * Switch confirmation callback method * 1.The messaging switch received a callback * 1.1 CorrelationData The ID and related information of the callback message are saved * 1.2 The switch receives the message ack=true * 1.3 cause - null * 2. Message sending switch accepts failed callback * 2.1 CorrelationData The ID and related information of the callback message are saved * 2.2 The switch receives the message ack = false * 2.3 cause - Reasons for failure */ @Override public void confirm(CorrelationData correlationData, boolean ack, String cause) { String id = correlationData != null ? correlationData.getId() : ""; if (ack){ log.info("I got it id Is:{}News of",id); }else { log.info("The switch has not received id: {}Message due to reason:{}",id,cause); } } //When the destination cannot be reached during message delivery, the message is returned to the producer //Fallback only occurs when the destination is unreachable @Override public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) { log.error("news{},Switched{}Return, return reason:{},routingKey: {}", new String(message.getBody()),exchange,replyText,routingKey); } @Override public void returnedMessage(ReturnedMessage returned) { } }
Backup switch
Modify configuration class
@Configuration public class ConfirmConfig { //Switch public static final String CONFIRM_EXCHANGE_NAME = "confirm_exchange"; //queue public static final String CONFIRM_QUEUE = "confirm_exchange"; //RoutingKey public static final String CONFIRM_ROUTING_KEY = "confirm_routing_key"; //Backup switch public static final String BACKUP_EXCHANGE_NAME = "backup_exchange"; //Backup queue public static final String BACKUP_QUEUE_NAME = "backup_queue"; //Alarm queue public static final String WARNING_QUEUE_NAME = "warning_queue"; //Claim switch @Bean public DirectExchange confirmExchange(){ //The confirmation switch cannot forward the confirmation message to the backup switch return ExchangeBuilder.directExchange(CONFIRM_EXCHANGE_NAME).durable(true) .withArgument("alternate-exchange",BACKUP_EXCHANGE_NAME).build(); } //Declaration queue @Bean public Queue confirmQueue(){ return QueueBuilder.durable(CONFIRM_QUEUE).build(); } //binding @Bean public Binding queueBindingExchange(@Qualifier("confirmExchange")DirectExchange confirmExchange, @Qualifier("confirmQueue")Queue confirmQueue){ return BindingBuilder.bind(confirmQueue).to(confirmExchange).with(CONFIRM_ROUTING_KEY); } //Backup switch @Bean public FanoutExchange backupExchange(){ return new FanoutExchange(BACKUP_EXCHANGE_NAME); } //Backup queue @Bean public Queue backupQueue(){ return QueueBuilder.durable(BACKUP_QUEUE_NAME).build(); } @Bean public Queue warningQueue(){ return QueueBuilder.durable(WARNING_QUEUE_NAME).build(); } //binding @Bean public Binding backupQueueBindingExchange(@Qualifier("backupExchange") FanoutExchange backupExchange, @Qualifier("backupQueue")Queue backupQueue){ return BindingBuilder.bind(backupQueue).to(backupExchange); } //binding @Bean public Binding warningQueueBindingExchange(@Qualifier("backupExchange") FanoutExchange backupExchange, @Qualifier("warningQueue")Queue warningQueue){ return BindingBuilder.bind(warningQueue).to(backupExchange); } }
Alarm consumer
@Component @Slf4j public class WarningConsumer { //Accept alarm information @RabbitListener(queues = ConfirmConfig.WARNING_QUEUE_NAME) public void receiveWarningMsg(Message message) { String msg = new String(message.getBody()); log.error("Alarm discovery non routable message:{}",msg); } }
Result analysis
When the mandatory parameter and the backup switch can be used together, if they are enabled at the same time, where will the message go? Who has the highest priority? The result above shows that the backup switch has the highest priority.