@RabbitListener用于多个类

时间:2018-05-11 08:55:09

标签: rabbitmq amqp spring-amqp spring-rabbit

我想知道Spring AMQP是否有可能在多个类中接收来自同一队列的消息,具体取决于有效负载类型。

我知道在类中使用@RabbitListener注释,然后在方法上放置@RabbitHandler,但我想在保留单个队列的同时将多个类中的消息处理的复杂性分开。

目前正在使用的版本:Spring AMQP v2.0.3以及RabbitMQ。

3 个答案:

答案 0 :(得分:2)

嗯,这是不可能的。您希望它的方式不会成为队列。 这实际上是设计单个侦听器并根据payload类型分发到其方法的架构决策。

作为一种解决方法,我建议您将逻辑从单个@RabbitListener类委托给这些业务服务:

@RabbitListener(queues = "foo")
public class MyListener {

    private final ServiceA serviceA;

    private final ServiceB serviceB;

    public MyListener(ServiceA serviceA, ServiceB serviceB) {
          this.serviceA = serviceA;
          this.serviceB = serviceB;
    }


    @RabbitHandler
    public void handleA(A a) {
         this.serviceA.handle(a);
    }

    @RabbitHandler
    public void handleB(B b) {
         this.serviceB.handle(b);
    }
}

答案 1 :(得分:0)

是的,但是需要一些不同的方法: 您需要监听通用的消息类型,进行一些切换以及自己的反序列化。您当然可以完全将该代码隐藏在某个地方(基类,注释...)

下面的示例可以扩展为收听其他类型的声音。 上面的示例将过滤A和B DTO类型。

void receive(ADTO dto)
{
    System.out.print(dto.url);
}

void receive(BDTO dto)
{
    System.out.print(dto.url);
}
@RabbitListener(queues = "your.queue.name")
public void listenMesssage(Message message) 
 {
    try 
    {
        String typeId = message.getMessageProperties().getHeaders().get("__TypeId__").toString();
        String contentType = message.getMessageProperties().getContentType();
        if (contentType != "application/json" || typeId == null || !typeId.contains(ADTO.class.toString()))
        {
            //TODO log warning
            System.out.print("type not supported by this service");
            return;
        }
        Object receivedObject = new Jackson2JsonMessageConverter().fromMessage(message);

        if (receivedObject instanceof ADTO)
        {
            receive((ADTO)receivedObject);
            System.out.print("ADTO");
        }
        //else

或者,您也可以像这样进行序列化:

....
String typeId = message.getMessageProperties().getHeaders().get("__TypeId__").toString();
byte[] binMsg =  message.getBody();
String strMsg  = new String(binMsg, StandardCharsets.UTF_8);
ObjectMapper mapper = new ObjectMapper();
if (typeId.contains("ADTO"))
{
   receive(mapper.readValue(strMsg, ADTO.class ));
}
else
...            

答案 2 :(得分:0)

或者,我发现,如果您的AQMP和Rabbit版本足够高 (mine = spring-rabit 2.1.3,spring-starter-aqmp 2.1.2),您可以执行以下变形:

@RabbitListener(id="multi", queues = "somequeuename")
public class SomeService 
{
    @RabbitHandler
    public void handleADTO(@Payload ADTO adto) {
         System.out.print(adto.url);
    }

    @RabbitHandler
    public void handleADTO2(@Payload ADTO2 adto) {
         System.out.print(adto.url);
    }
}

但是,开箱即用不起作用。您需要配置另一个“豆袋”:

@Bean
public SimpleRabbitListenerContainerFactory myFactory(
        SimpleRabbitListenerContainerFactoryConfigurer configurer, ConnectionFactory connectionFactory) {
    SimpleRabbitListenerContainerFactory factory =
            new SimpleRabbitListenerContainerFactory();
    configurer.configure(factory, connectionFactory);
    return factory;
}

@Bean
Jackson2JsonMessageConverter jsonMessageConverter() {
    return new Jackson2JsonMessageConverter();
}

@Bean
RabbitTemplate rabbitTemplate(Jackson2JsonMessageConverter converter, ConnectionFactory connectionFactory) {
    RabbitTemplate template = new RabbitTemplate(connectionFactory);
    template.setMessageConverter(new Jackson2JsonMessageConverter());
    return template;
}

只需将其放入您的应用或其他类中即可。

另请参见

https://docs.spring.io/spring-amqp/docs/current/reference/html/