此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring AMQP 3.2.0spring-doc.cadn.net.cn

回复管理

现有的支持MessageListenerAdapteralready 允许您的方法具有非 void 返回类型。 在这种情况下,调用的结果将封装在发送到ReplyToAddress标头,或发送到侦听程序上配置的默认地址。 您可以使用@SendTo消息抽象的注释。spring-doc.cadn.net.cn

假设我们的processOrder方法现在应该返回一个OrderStatus,我们可以这样写来自动发送回复:spring-doc.cadn.net.cn

@RabbitListener(destination = "myQueue")
@SendTo("status")
public OrderStatus processOrder(Order order) {
    // order processing
    return status;
}

如果需要以独立于传输的方式设置其他 Headers,则可以返回Message相反,如下所示:spring-doc.cadn.net.cn

@RabbitListener(destination = "myQueue")
@SendTo("status")
public Message<OrderStatus> processOrder(Order order) {
    // order processing
    return MessageBuilder
        .withPayload(status)
        .setHeader("code", 1234)
        .build();
}

或者,您可以使用MessagePostProcessorbeforeSendReplyMessagePostProcessorsContainer Factory 属性来添加更多标头。 从版本 2.2.3 开始,被调用的 bean/方法在回复消息中可用,它可以在消息后处理器中使用,将信息传回给调用者:spring-doc.cadn.net.cn

factory.setBeforeSendReplyPostProcessors(msg -> {
    msg.getMessageProperties().setHeader("calledBean",
            msg.getMessageProperties().getTargetBean().getClass().getSimpleName());
    msg.getMessageProperties().setHeader("calledMethod",
            msg.getMessageProperties().getTargetMethod().getName());
    return m;
});

从版本 2.2.5 开始,您可以配置ReplyPostProcessor在发送回复消息之前对其进行修改;它在correlationId标头已设置为匹配请求。spring-doc.cadn.net.cn

@RabbitListener(queues = "test.header", group = "testGroup", replyPostProcessor = "echoCustomHeader")
public String capitalizeWithHeader(String in) {
    return in.toUpperCase();
}

@Bean
public ReplyPostProcessor echoCustomHeader() {
    return (req, resp) -> {
        resp.getMessageProperties().setHeader("myHeader", req.getMessageProperties().getHeader("myHeader"));
        return resp;
    };
}

从版本 3.0 开始,您可以在容器工厂而不是 Comments 上配置后处理器。spring-doc.cadn.net.cn

factory.setReplyPostProcessorProvider(id -> (req, resp) -> {
    resp.getMessageProperties().setHeader("myHeader", req.getMessageProperties().getHeader("myHeader"));
    return resp;
});

idparameter 是侦听器 ID。spring-doc.cadn.net.cn

注释上的设置将取代出厂设置。spring-doc.cadn.net.cn

@SendTovalue 被假定为回复exchangeroutingKey对,它跟在exchange/routingKey模式 其中,可以省略其中一个部分。 取值如下:spring-doc.cadn.net.cn

  • thing1/thing2:这replyToexchange 和routingKey.thing1/:这replyToexchange 和默认值 (空)routingKey.thing2/thing2:这replyTo routingKey和默认 (空) 交换。 或空的:/replyTodefault exchange 和默认的routingKey.spring-doc.cadn.net.cn

此外,您还可以使用@SendTo没有value属性。 这种情况等于空的sendTo模式。@SendTo仅在入站邮件没有replyToAddress财产。spring-doc.cadn.net.cn

从版本 1.5 开始,@SendTovalue 可以是 bean 初始化 SPEL 表达式,如以下示例所示:spring-doc.cadn.net.cn

@RabbitListener(queues = "test.sendTo.spel")
@SendTo("#{spelReplyTo}")
public String capitalizeWithSendToSpel(String foo) {
    return foo.toUpperCase();
}
...
@Bean
public String spelReplyTo() {
    return "test.sendTo.reply.spel";
}

表达式的计算结果必须为String,可以是简单的队列名称(发送到默认 exchange)或使用 表单exchange/routingKey如前面的示例所述。spring-doc.cadn.net.cn

#{…​}expression 在初始化期间计算一次。

对于动态回复路由,邮件发件人应包含reply_tomessage 属性或使用替代 运行时 SpEL 表达式(在下一个示例后描述)。spring-doc.cadn.net.cn

从版本 1.6 开始,@SendTo可以是在运行时根据请求评估的 SPEL 表达式 和 reply,如下例所示:spring-doc.cadn.net.cn

@RabbitListener(queues = "test.sendTo.spel")
@SendTo("!{'some.reply.queue.with.' + result.queueName}")
public Bar capitalizeWithSendToSpel(Foo foo) {
    return processTheFooAndReturnABar(foo);
}

SPEL 表达式的运行时性质用!{…​}分隔符。 评估上下文#rootobject 具有三个属性:spring-doc.cadn.net.cn

上下文有一个 map 属性访问器、一个标准类型转换器和一个 bean 解析器,它允许 context 被引用(例如@someBeanName.determineReplyQ(request, result)).spring-doc.cadn.net.cn

总之,#{…​}在初始化期间计算一次,使用#rootobject 是应用程序上下文。 Bean 由其名称引用。!{…​}在运行时针对每条消息进行评估,其中根对象具有前面列出的属性。 Bean 以其名称引用,前缀为 .@spring-doc.cadn.net.cn

从版本 2.1 开始,还支持简单的属性占位符(例如,${some.reply.to}). 对于早期版本,可以使用以下方法作为解决方法,如下例所示:spring-doc.cadn.net.cn

@RabbitListener(queues = "foo")
@SendTo("#{environment['my.send.to']}")
public String listen(Message in) {
    ...
    return ...
}