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转换为某种类型"。
答案 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());
}
}
也许您可以在侦听器中设置断点并向下看堆栈,以确切了解哪个转换器连接到侦听器适配器。