我曾经有一个@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;
}