@RabbitListener与containerFactory

时间:2017-11-20 13:25:24

标签: rabbitmq spring-rabbitmq

RabbitMQ消息到达时带有类型信息:

headers:    
__ContentTypeId__:  java.lang.Object
__TypeId__: java.util.ArrayList

我在代码中有这两个容器工厂bean - 默认一个使用转换器,另一个不使用:

@Bean
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory) {
final SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
    factory.setConnectionFactory(connectionFactory);
    final Jackson2JsonMessageConverter messageConverter = new Jackson2JsonMessageConverter();
    factory.setMessageConverter(messageConverter);
    return factory;
}

@Bean
public SimpleRabbitListenerContainerFactory rawContainerFactory(ConnectionFactory connectionFactory) {
    final SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
    factory.setConnectionFactory(connectionFactory);
    return factory;
}

场景1.听众。

@RabbitListener(queues = "#{@myQueueBean}")
public void persistMessage(Message message) {
    .....
}

当我检查到达监听器的内容时​​,message.payload是ArrayList,里面有HashMaps。这看起来不错,似乎是使用rabbitListenerContainerFactory作为默认值。

场景2.我改为使用不带转换器的containerFactory:

@RabbitListener(queues = "#{@myQueueBean}", containerFactory = "rawContainerFactory")
public void persistMessage(Message message) {
    .....
}

当我检查到达的内容时,message.payload现在是带有消息内容的byte []。再看起来还不错。

场景3.我更改为显式使用默认的containerFactory:

@RabbitListener(queues = "#{@myQueueBean}", containerFactory = "rabbitListenerContainerFactory")
public void persistMessage(Message message) {
    .....
}

当我检查到达的内容时,message.payload再次是带有消息内容的byte []。这听起来很意外,我希望在场景1中使用ArrayList。

现在我在第一个bean中注释掉messageConverter:

@Bean
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory) {
    SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
    factory.setConnectionFactory(connectionFactory);
//  Jackson2JsonMessageConverter messageConverter = new Jackson2JsonMessageConverter();
//  factory.setMessageConverter(messageConverter);
    return factory;
}

@Bean
public SimpleRabbitListenerContainerFactory rawContainerFactory(ConnectionFactory connectionFactory) {
    final SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
    factory.setConnectionFactory(connectionFactory);
    return factory;
}

场景4.再次听取

@RabbitListener(queues = "#{@myQueueBean}")
public void persistMessage(Message message) {
    .....
}

当我检查到达的内容时,我希望message.payload为byte [](默认使用containerfactory,没有像场景2那样的转换器),但实际上我得到一个逗号分隔数字的字符串。这听起来不对。

场景5.我改为明确使用没有转换器的默认containerFactory:

@RabbitListener(queues = "#{@myQueueBean}", containerFactory = "rabbitListenerContainerFactory")
public void persistMessage(Message message) {
    .....
}

当我检查到达的内容时,message.payload现在是带有消息内容的byte []。这就像场景2,看起来不错。

场景6.使用" rawContainerFactory",结果现在逻辑上需要一个byte []数组。

场景7.使用" rawContainerFactory"并添加杰克逊转换器。结果是ArrayList。在场景3结果之后非常出乎意料。

上面的结果看起来非常不一致。 " rabbitListenerContainerFactory"有一些神奇之处。这促使我说 - 忘记它并在显式配置中使用自己的自定义工厂。除非有人设法解释这种魔力。

更新:我再也无法重现这个问题了,这又是另一个神奇的原因。场景3和场景4问题都消失了,除了添加一个测试用例以使用RabbitTemplate将消息发送到队列之外,我几乎没有做任何事情(但仍然使用队列中的真正大jsons进行测试)。之前和现在,我正在使用Eclipse和Idea对磁盘上的相同物理项目代码进行测试。另外一个注意事项,我的样本中的所有听众都使用非通用的Message类型参数。我明确地做了这个,因为在某些场景中添加了任何特定类型(如果我没记错的话可能是场景1或4) - 甚至< ? >正在改变它的行为,以至于消息甚至无法传达给我的听众,并且日志中会出现错误,说明某些内容"无法将START_OBJECT转换为某种类型"。

1 个答案:

答案 0 :(得分:0)

我无法重现您引用的行为。一切都按照我的预期运作。

@SpringBootApplication
public class So47393130Application {

    public static void main(String[] args) {
        SpringApplication.run(So47393130Application.class, args).close();
    }

    @Bean
    public ApplicationRunner runner(RabbitTemplate rabbitTemplate) {
        return args -> {
            rabbitTemplate.convertAndSend("foo", "", new ArrayList<>(Arrays.asList("foo", "bar")));
            Thread.sleep(5_000);
        };
    }

    @Bean
    public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory) {
        final SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        final Jackson2JsonMessageConverter messageConverter = new Jackson2JsonMessageConverter();
        factory.setMessageConverter(messageConverter);
        return factory;
    }

    @Bean
    public SimpleRabbitListenerContainerFactory rawContainerFactory(ConnectionFactory connectionFactory) {
        final SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        return factory;
    }

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

    @Bean
    public Queue foo() {
        return new Queue("foo");
    }

    @Bean
    public Queue bar() {
        return new Queue("bar");
    }

    @Bean
    public Queue baz() {
        return new Queue("baz");
    }

    @Bean
    public FanoutExchange exchange() {
        return new FanoutExchange("foo");
    }

    @Bean
    public Binding fooBinding() {
        return BindingBuilder.bind(foo()).to(exchange());
    }

    @Bean
    public Binding barBinding() {
        return BindingBuilder.bind(bar()).to(exchange());
    }

    @Bean
    public Binding bazBinding() {
        return BindingBuilder.bind(baz()).to(exchange());
    }

    @RabbitListener(queues = "foo")
    public void foo(Message<?> in) {
        System.out.println("foo:" + in.getPayload());
    }

    @RabbitListener(queues = "bar", containerFactory = "rawContainerFactory")
    public void bar(Message<?> in) {
        System.out.println("bar:" + in.getPayload());
    }

    @RabbitListener(queues = "baz", containerFactory = "rabbitListenerContainerFactory")
    public void baz(Message<?> in) {
        System.out.println("baz:" + in.getPayload());
    }

}

也许您可以在侦听器中设置断点并向下看堆栈,以确切了解哪个转换器连接到侦听器适配器。