为什么我不能通过spring-boot-starter-amqp来获得用户方的correlationId?

时间:2018-12-19 18:16:10

标签: spring-boot spring-amqp

我将RabbitTemplate发送消息与自己生成的CorrelationData一起使用。我已经在cofirmCallBack中收到了correlationId,但是在消费者端却无法收到它。

我用2.0.3.RELEASE和2.1.0.RELEASE测试了这个问题,结果与上面的描述一致。

rabbitmq配置

@Configuration
public class RabbitMQConfig {

    @Value("${mq.rabbit.addresses}")
    private String addresses;

    @Value("${mq.rabbit.username}")
    private String username;

    @Value("${mq.rabbit.password}")
    private String password;

    @Value("${mq.rabbit.virtualHost}")
    private String virtualHost;

    @Value("${mq.rabbit.sessionCacheSize}")
    private int sessionCacheSize;

    @Bean
    public ConnectionFactory connectionFactory() {
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        connectionFactory.setAddresses(addresses);// addresses list of addresses with form "host[:port],..."
        connectionFactory.setVirtualHost(virtualHost);
        connectionFactory.setPublisherConfirms(true);
        connectionFactory.setPublisherReturns(true);
        connectionFactory.setChannelCacheSize(sessionCacheSize);
        connectionFactory.setUsername(username);
        connectionFactory.setPassword(password);
        return connectionFactory;
    }

    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public RabbitTemplate rabbitTemplate(MessageConverter messageConverter) {
        RabbitTemplate template = new RabbitTemplate(connectionFactory());
        template.setMessageConverter(messageConverter);
        template.setMandatory(true);
        template.setConfirmCallback(new ConfirmCallbackListener());
        template.setReturnCallback(new ReturnCallBackListener());
        return template;
    }

    @Bean
    public MessageConverter messageConverter(ObjectMapper customMapper) {
        return new Jackson2JsonMessageConverter(customMapper);
    }

    @Bean
    public Queue testQueue() {
        return new Queue("test-queue", true);
    }

    @Bean
    public TopicExchange defaultExchange() {
        return new TopicExchange("test-exchange", true, false);
    }

    @Bean
    public Binding bindingExchangeCommon(Queue testQueue, TopicExchange defaultExchange) {
        return BindingBuilder.bind(testQueue).to(defaultExchange).with("test");
    }

    @Bean
    public SimpleMessageListenerContainer testMessageContainer(ConnectionFactory connectionFactory) {
        SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
        container.setQueueNames("test-queue");
        container.setExposeListenerChannel(true);
        container.setPrefetchCount(250);
        container.setMaxConcurrentConsumers(20);
        container.setConcurrentConsumers(10);
        container.setAcknowledgeMode(AcknowledgeMode.MANUAL);
        container.setMessageListener(new TestMessageListener());
        return container;
    }
}

确认回调

public class ConfirmCallbackListener implements RabbitTemplate.ConfirmCallback {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        if(!ack) {
            logger.info("send message ack failed: " + cause + " -> ID: " + String.valueOf(correlationData));
        }else {
            logger.info("send message ack success -> ID: " + String.valueOf(correlationData));
        }
    }
}

返回回调

public class ReturnCallBackListener implements RabbitTemplate.ReturnCallback{

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
        logger.info("send message failed...");
    }

}

消息监听器

public class TestMessageListener implements ChannelAwareMessageListener {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    public void onMessage(Message message, Channel channel) throws Exception {
        try {
            // Here: get CorrelationId is always null
            logger.info("handle message: {} -> ID: {}" , new String(message.getBody(), "UTF-8"), 
                message.getMessageProperties().getCorrelationId());
            if(true) {
                channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
                logger.info("listener ack message completed");
            }else {
                channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
            }
        } catch (Exception e) {
            logger.error("handle test message error", e);
            channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
        }
    }

}

发送消息

@RestController
@RequestMapping("/rabbitmq")
public class RabbitmqCtrl {

    private AtomicLong atoId = new AtomicLong();

    @Resource
    private RabbitTemplate rabbitTemplate;

    @PostMapping("sendMsg")
    public String sendMsg(@RequestBody String content) {
        Message message = new Message();
        message.setId(String.valueOf(atoId.incrementAndGet()));
        message.setContent(content);
        rabbitTemplate.convertAndSend("test-exchange", "test", message, new CorrelationData(String.valueOf(atoId.get())));
        return "success";
    }
}

我尝试将CorrelationDataPostProcessor设置为RabbitTemplate,如下所示:

template.setCorrelationDataPostProcessor(new CorrelationDataPostProcessor() {
            @Override
            public CorrelationData postProcess(Message message, CorrelationData correlationData) {
                if(correlationData != null) {
                    message.getMessageProperties().setCorrelationId(correlationData.getId());
                }
                return correlationData;
            }
        });

通过这种方式,我可以获得CorelationID,但是我认为由于在发送消息时已经设置了ID,所以我不必这样做。还有其他更合理的解释吗?

1 个答案:

答案 0 :(得分:1)

<DataTrigger Binding="{Binding ElementName=MyWPFCombo, Path=SelectedValue}" Value="10"> <Setter Property="Text" Value="Select the old items:" /> </DataTrigger> 不会通过网络发送,除非您使用自定义CorrelationData明确声明,就像您对MessagePostProcessor所做的那样。 默认实现是这样的:

CorrelationDataPostProcessor

您看到default Message postProcessMessage(Message message, Correlation correlation) { return postProcessMessage(message); } 被完全忽略。

因此,要向用户端发送相关信息,我们实际上必须提供自定义correlation并将其注入MessagePostProcessor中。