此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 Spring AMQP 3.2.6! |
回复管理
现有支持MessageListenerAdapter
已经让你的方法具有非 void 返回类型。
在这种情况下,调用的结果将封装在发送到ReplyToAddress
标头,或侦听器上配置的默认地址。
您可以使用@SendTo
消息传递抽象的注释。
假设我们的processOrder
方法现在应该返回一个OrderStatus
,我们可以写成这样,自动发送回复:
@RabbitListener(destination = "myQueue")
@SendTo("status")
public OrderStatus processOrder(Order order) {
// order processing
return status;
}
如果需要以与传输无关的方式设置其他标头,则可以返回Message
相反,类似于以下内容:
@RabbitListener(destination = "myQueue")
@SendTo("status")
public Message<OrderStatus> processOrder(Order order) {
// order processing
return MessageBuilder
.withPayload(status)
.setHeader("code", 1234)
.build();
}
或者,您可以使用MessagePostProcessor
在beforeSendReplyMessagePostProcessors
container factory 属性来添加更多标头。
从版本 2.2.3 开始,被调用的 bean/method 在回复消息中可用,它可以在消息后处理器中使用,以将信息传达给调用者:
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
标头已设置为匹配请求。
@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 版开始,您可以在容器工厂而不是注释上配置后处理器。
factory.setReplyPostProcessorProvider(id -> (req, resp) -> {
resp.getMessageProperties().setHeader("myHeader", req.getMessageProperties().getHeader("myHeader"));
return resp;
});
这id
参数是监听器 ID。
注释上的设置将取代出厂设置。
这@SendTo
value 假定为回复exchange
和routingKey
对后面的exchange/routingKey
模式
其中一个部分可以省略。
有效值如下:
-
thing1/thing2
:这replyTo
exchange 和routingKey
.thing1/
:这replyTo
交换和默认值(空)routingKey
.thing2
或/thing2
:这replyTo
routingKey
和默认(空)交易所。 或空:/
replyTo
默认交换和默认routingKey
.
此外,您还可以使用@SendTo
没有value
属性。
这种情况等于空的sendTo
模式。@SendTo
仅当入站消息没有replyToAddress
财产。
从 1.5 版开始,@SendTo
value 可以是 bean 初始化 SpEL 表达式,如以下示例所示:
@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/routingKey
如前面示例之前所述。
这#{…} expression 在初始化期间计算一次。 |
对于动态回复路由,邮件发送方应包含reply_to
message 属性或使用 alternate
runtime SpEL 表达式(在下一个示例之后描述)。
从 1.6 版本开始,@SendTo
可以是在运行时针对请求进行评估的 SpEL 表达式
并回复,如以下示例所示:
@RabbitListener(queues = "test.sendTo.spel")
@SendTo("!{'some.reply.queue.with.' + result.queueName}")
public Bar capitalizeWithSendToSpel(Foo foo) {
return processTheFooAndReturnABar(foo);
}
SpEL 表达式的运行时性质用!{…}
分隔符。
评估上下文#root
object 具有三个属性:
-
request
:这o.s.amqp.core.Message
request 对象。 -
source
:这o.s.messaging.Message<?>
转换后。 -
result
:方法结果。
上下文有一个映射属性访问器、一个标准类型转换器和一个 bean 解析器,它允许
上下文(例如,@someBeanName.determineReplyQ(request, result)
).
综上所述,#{…}
在初始化期间评估一次,使用#root
object 是应用程序上下文。
豆子由其名称引用。!{…}
在运行时为每条消息进行评估,根对象具有前面列出的属性。
Bean 用它们的名称引用,前缀为 .@
从 2.1 版开始,还支持简单的属性占位符(例如${some.reply.to}
).
对于早期版本,可以使用以下方法作为解决方法,如以下示例所示:
@RabbitListener(queues = "foo")
@SendTo("#{environment['my.send.to']}")
public String listen(Message in) {
...
return ...
}