Spring AMQP检测到在@RabbitHandler中使用的类似负载类型



我曾经有一个@RabbitListener,它可以像这样工作:

@Component
public class AppointmentMessageListener {
@RabbitListener(queues = "${rabbitmq.immediateQueueName}")
public void receiveImmediateAppointmentMessage(AppointmentMessage appointmentMessage) {
// Do something
}
}

现在我想在同一个队列上有一个不同类型的消息,我像文档所说的那样尝试了一下:

@Component
@RabbitListener(queues = "${rabbitmq.immediateQueueName}")
public class AppointmentMessageListener {
@RabbitHandler
public void receiveImmediateAppointmentMessage(AppointmentMessage appointmentMessage) {
// Do something
}
@RabbitHandler
public void receiveImmediateAppointmentMessage(AppointmentDeleteMessage appointmentDeleteMessage) {
// Do something else
}
}

这不起作用,我得到了org.springframework.amqp.AmqpException: No method found for class java.util.LinkedHashMap

JSON如下所示,两种类型之间的区别仅在于object结构。我无法控制消息的结构。有什么方法可以检测出在多方法侦听器中使用的正确类型吗?

{
"key":"event-message-resource.immediate",
"creationTimestamp":1643804135376,
"object": {
// here is the object I am interested in
}
}

除了交换、队列和路由密钥声明外,我还使用以下配置

@Bean
public Jackson2JsonMessageConverter jsonMessageConverter() {
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().build();
return new Jackson2JsonMessageConverter(objectMapper);
}
@Bean
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(SimpleRabbitListenerContainerFactoryConfigurer configurer,
         ConnectionFactory connectionFactory,
         AuthenticationRabbitListenerAdvice rabbitListenerAdvice) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
configurer.configure(factory, connectionFactory);
factory.setAdviceChain(combineAdvice(factory.getAdviceChain(), rabbitListenerAdvice));
return factory;
}

框架在使用@RabbitHandler时无法推断目标类型,因为它使用类型来选择方法。在执行方法选择之前,必须转换JSON。

请参阅https://docs.spring.io/spring-amqp/docs/current/reference/html/#Jackson2JsonMessageConverter-来自消息

您需要使用消息中的某些内容来确定要创建的类型。

根据尊敬的Gary Russell的回答和他在这里的帖子中的回答,我通过对ClassMapper进行子类化并根据路由键决定类型来实现它。

@Component
@RequiredArgsConstructor
public class CustomClassMapper extends DefaultJackson2JavaTypeMapper {
@Value("${rabbitmq.deleteRoutingKey}")
private final String deleteRoutingKey;
@NonNull
@Override
public Class<?> toClass(MessageProperties properties) {
String routingKey = properties.getReceivedRoutingKey();
if (deleteRoutingKey.equals(routingKey)) {
return AppointmentDeleteMessage.class;
}
return AppointmentMessage.class;
}
}

然后我在messageConverter中设置了classMapper

@Bean
public Jackson2JsonMessageConverter jsonMessageConverter(CustomClassMapper customClassMapper) {
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().build();
Jackson2JsonMessageConverter messageConverter = new Jackson2JsonMessageConverter(objectMapper);
messageConverter.setClassMapper(customClassMapper);
return messageConverter;
}

最新更新