rabbitmq客戶端發送消息首先發送的交換器exchange,然後通過路由鍵routingKey和bindingKey比較判定需要將消息發送到那個隊列queue上;在這個過程有兩個地方消息可能丟失,第一消息發送到交換器exchange的過程,第二消息從交換器exchange發送到隊列queue的過程;
1.publiser-confirm模式可以確保生產者到交換器exchange消息有沒有發送成功
#設置此屬性配置可以確保消息成功發送到交換器
spring.rabbitmq.publisher-confirms=true
2.publisher-return模式可以在消息沒有被路由到指定的queue時將消息返回,而不是丟棄
#可以確保消息在未被隊列接收時返回
spring.rabbitmq.publisher-returns=true
在使用上面的屬性配置時通常會和mandatory屬性配合一起使用:
#指定消息在沒有被隊列接收時是否強行退回還是直接丟棄
spring.rabbitmq.template.mandatory=true
到這裏你可能會有一個疑問,這兩個配置都是指定未找到合適隊列時將消息退回,究竟是如何分別起作用呢?接下來我們看下RabbitAutoConfiguration自動化配置類就清楚了:
@Bean
@ConditionalOnSingleCandidate(ConnectionFactory.class)
@ConditionalOnMissingBean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
PropertyMapper map = PropertyMapper.get();
RabbitTemplate template = new RabbitTemplate(connectionFactory);
MessageConverter messageConverter = (MessageConverter)this.messageConverter.getIfUnique();
if (messageConverter != null) {
template.setMessageConverter(messageConverter);
}
//設置rabbitmq處理未被queue接收消息的模式
template.setMandatory(this.determineMandatoryFlag());
Template properties = this.properties.getTemplate();
if (properties.getRetry().isEnabled()) {
template.setRetryTemplate((new RetryTemplateFactory((List)this.retryTemplateCustomizers.orderedStream().collect(Collectors.toList()))).createRetryTemplate(properties.getRetry(), Target.SENDER));
}
properties.getClass();
map.from(properties::getReceiveTimeout).whenNonNull().as(Duration::toMillis).to(template::setReceiveTimeout);
properties.getClass();
map.from(properties::getReplyTimeout).whenNonNull().as(Duration::toMillis).to(template::setReplyTimeout);
properties.getClass();
map.from(properties::getExchange).to(template::setExchange);
properties.getClass();
map.from(properties::getRoutingKey).to(template::setRoutingKey);
properties.getClass();
map.from(properties::getDefaultReceiveQueue).whenNonNull().to(template::setDefaultReceiveQueue);
return template;
}
//判定是否將未找到合適queue的消息退回
private boolean determineMandatoryFlag() {
/**
* 獲取spring.rabbitmq.template.mandatory屬性配置;
* 這裏面會有三種可能,爲null、false、true
* 而只有在mandatory爲null時纔會讀取publisher-return屬性值
**/
Boolean mandatory = this.properties.getTemplate().getMandatory();
return mandatory != null ? mandatory : this.properties.isPublisherReturns();
}
閱讀上面的源碼可以獲取如下信息:
- spring.rabbitmq.template.mandatory屬性的優先級高於spring.rabbitmq.publisher-returns的優先級
- spring.rabbitmq.template.mandatory屬性可能會返回三種值null、false、true,
- spring.rabbitmq.template.mandatory結果爲true、false時會忽略掉spring.rabbitmq.publisher-returns屬性的值
- spring.rabbitmq.template.mandatory結果爲null(即不配置)時結果由spring.rabbitmq.publisher-returns確定
GitHub地址:https://github.com/mingyang66/spring-parent/tree/master/doc/rabbitmq