Spring boot 仅从@RabbitListener获取特定消息
我有一个向RabbitMQ发送消息的遗留系统。 系统只使用一个队列:Spring boot 仅从@RabbitListener获取特定消息,spring-boot,spring-amqp,spring-rabbit,Spring Boot,Spring Amqp,Spring Rabbit,我有一个向RabbitMQ发送消息的遗留系统。 系统只使用一个队列:q.finance.invoice,但它有两种消息类型,其中消息类型在标头上可用 第一类 Type : invoice.created { "field_1" : "", "field_2" : "", } 第二类 Type : invoice.paid { "field_5" : "", "field_6" : "", } 因此,现在我的消费者需要根据数据类型有选择地处理消息。 Spring有@Rabbi
q.finance.invoice
,但它有两种消息类型,其中消息类型在标头上可用
第一类
Type : invoice.created
{
"field_1" : "",
"field_2" : "",
}
第二类
Type : invoice.paid
{
"field_5" : "",
"field_6" : "",
}
因此,现在我的消费者需要根据数据类型有选择地处理消息。
Spring有@RabbitHandler
可以做到这一点。。。如果消息是由spring发布的。
但是我不能使用@RabbitHandler
注释。
我认为这是因为@RabbitHandler
正在基于旧式系统中不存在的\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
如何模拟这种@RabbitHandler
行为(根据其类型获取数据)
所以我使用@RabbitListener
来使用消息。
但是@RabbitListener
正在接收所有类型的消息。
我们使用@RabbitListener
的另一个原因是,我们的错误处理程序依赖于消息
和频道
我们的基本方法是:
@RabbitListener(queues=“q.finance.invoice”)
public void listenInvoicePaid(消息消息、频道、@Header(AmqpHeaders.DELIVERY_标记)长标记){
//将消息体JSON字符串转换为对象
//处理它
}
我正在尝试根据类型进行手动拒绝,这很有效。但我确信,当我有许多侦听器或队列时,它是不可伸缩的
import java.io.IOException;
导入org.apache.commons.lang3.StringUtils;
导入org.slf4j.Logger;
导入org.slf4j.LoggerFactory;
导入org.springframework.amqp.core.Message;
导入org.springframework.amqp.rabbit.annotation.RabbitListener;
导入org.springframework.amqp.support.AmqpHeaders;
导入org.springframework.messaging.handler.annotation.Header;
导入org.springframework.stereotype.Service;
导入com.rabbitmq.client.Channel;
@服务
公共类InvoiceListenerOnMethod{
私有静态最终记录器log=LoggerFactory.getLogger(InvoiceListenerOnMethod.class);
@RabbitListener(queues=“q.finance.invoice”)
public void listenInvoiceCreated(消息消息、频道、@Header(AmqpHeaders.DELIVERY_标记)长标记)
抛出IOException{
如果(!StringUtils.equalsIgnoreCase(“invoice.created”,message.getMessageProperties().getType())){
log.warn(“[on方法]拒绝创建的发票:{}”,消息);
channel.basicject(标记,true);
返回;
}
info(“[on方法]创建的侦听发票:{}”,消息);
}
@RabbitListener(queues=“q.finance.invoice”)
public void listenInvoicePaid(消息消息、频道、@Header(AmqpHeaders.DELIVERY_标记)长标记)
抛出IOException{
如果(!StringUtils.equalsIgnoreCase(“invoice.paid”,message.getMessageProperties().getType())){
log.warn(“[on Method]拒绝支付的发票:{}”,消息);
channel.basicject(标记,true);
返回;
}
log.info(“[on方法]监听发票:{}”,消息);
}
}
请看,如果我有4条消息(付费创建),侦听器可以运行4次以上,因为我们无法控制谁将接收哪条消息。因此,对于listenInvoicePaid()
- 拒绝
- 拒绝
- ack()
- 拒绝
- ack()
同样,ack()之前的多次拒绝()也可以在listenInvoiceCreated()中发生
因此,在所有信息正确处理之前,我总共可以收到10条左右的信息
有没有修复代码的建议?我还没有使用rabbit的spring integration,但总而言之,拥有一个处理不同消息类型的单一队列的想法听起来有问题:
许多消费者可能会收到他们无法处理的类型的消息,并且必须拒绝它们,这样消息就会返回到rabbit,然后一次又一次。。。所有集群的性能都可能因此而恶化
所以我认为有两条路可以走:
- 实现可以处理两种消息类型的单个侦听器。无需更改Rabbit,但在java方面可能是一个具有挑战性的重构
- 幸运的是,rabbitmq在路由消息方面非常灵活。将exchange配置为根据路由密钥、头将A类型的消息路由到队列A,将B类型的消息路由到队列B,无论什么,Rabbit中都有不同类型的exchange,您肯定会找到适合您的最佳配置
我个人会选择第二条路径。我没有使用rabbit的spring集成,但总的来说,拥有一个处理不同消息类型的单一队列的想法听起来像是有问题的:
许多消费者可能会收到他们无法处理的类型的消息,并且必须拒绝它们,这样消息就会返回到rabbit,然后一次又一次。。。所有集群的性能都可能因此而恶化
所以我认为有两条路可以走:
- 实现可以处理两种消息类型的单个侦听器。无需更改Rabbit,但在java方面可能是一个具有挑战性的重构
- 幸运的是,rabbitmq在路由消息方面非常灵活。将exchange配置为根据路由密钥、头将A类型的消息路由到队列A,将B类型的消息路由到队列B,无论什么,Rabbit中都有不同类型的exchange,您肯定会找到适合您的最佳配置
我个人会选择第二条路径。您可以向容器工厂的afterReceiveMessagePostProcessor
属性添加MessagePostProcessor
。在邮政专业