|
该版本仍在开发中,尚未被视为稳定。请使用最新的稳定版本,使用 Spring AMQP 4.0.0! |
回复管理
现有的支持MessageListener适配器你的方法已经允许非无效返回类型。
在这种情况下,调用的结果会封装在发送到指定地址的消息中回复地址原始消息的头部,或是监听器配置的默认地址。
你可以通过使用@SendTo消息抽象的注释。
假设我们的进程顺序方法现在应返回订单状态,我们可以这样写成,自动发送回复:
@RabbitListener(destination = "myQueue")
@SendTo("status")
public OrderStatus processOrder(Order order) {
// order processing
return status;
}
如果你需要以与传输无关的方式设置额外的头部,你可以返回消息而是类似以下内容:
@RabbitListener(destination = "myQueue")
@SendTo("status")
public Message<OrderStatus> processOrder(Order order) {
// order processing
return MessageBuilder
.withPayload(status)
.setHeader("code", 1234)
.build();
}
或者,你也可以使用消息后处理器在beforeSendReplyMessagePostProcessors用container factory属性添加更多头部。
从2.2.3版本开始,被调用的豆/方法可在回复消息中提供,该回复可在消息后处理器中将信息反馈给呼叫者:
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版本开始,你可以配置回复后处理器在回复消息发送前修改;它以关联Id首部已被设置为匹配请求。
@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。
注释中的设置会优先于出厂设置。
这@SendTo假设 值为回复交换和路由键跟随交换/路由密钥模式
其中一个部分可以省略。
有效数值如下:
-
东西1/东西2:这回复交换与路由键.事情1/:这回复交换与默认(空)路由键.东西2或/thing2:这回复路由键以及默认的(空交换)。 或空的:该/回复默认交换与默认路由键.
另外,你也可以使用@SendTo没有值属性。
此情况等于 空发送模式。@SendTo仅当入站消息没有回复地址财产。
从1.5版本开始,@SendTovalue 可以是豆初始化的 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";
}
该表达式必须取值为字符串可以是一个简单的队列名称(发送到默认交换机),也可以是
形式交换/路由密钥如前述例子所述。
这#{…}表达式在初始化时只被评估一次。 |
对于动态回复路由,消息发送方应包含reply_to消息属性或使用替代
运行时 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表达式的对象具有三个性质:
-
请求:这o.s.amqp.core.Message请求对象。 -
源:这o.s.messaging.Message<?>经过皈依。 -
结果:方法结果。
上下文包含一个映射属性附属器、一个标准类型转换器和一个豆子解析器,使其他豆子能够在
上下文应被引用(例如,@someBeanName.determineReplyQ(请求,结果)).
总之,#{…}在初始化过程中被评估一次,其中#root对象是应用上下文。
Beans名称被提及。!{…}在运行时对每个消息进行评估,根对象具有前面列出的属性。
豆子以名称命名,前缀为 。@
从2.1版本开始,也支持简单的属性占位符(例如,${some.reply.to}).
对于早期版本,以下示例可以作为变通方法:
@RabbitListener(queues = "foo")
@SendTo("#{environment['my.send.to']}")
public String listen(Message in) {
...
return ...
}