问题描述
我有两个不同的java spring 项目,它们通过rabbitmq 进行通信。我正在尝试发送一个 java 对象,但收到此错误消息:
org.springframework.amqp.rabbit.support.ListenerExecutionFailedException: Listener threw exception
Caused by: org.springframework.amqp.support.converter.MessageConversionException: Failed to resolve class name. Class not found [com.thesis.gamamicroservices.productservice.dto.ProductCreatedDTO]
我知道问题出在生产者和消费者中应该相同的类路径中,但是由于每个项目具有不同的名称,即使它们具有完全相同的类,我也无法使类路径相同在相同的包内。
类路径存在于标题中:
headers={__TypeId__=com.thesis.gamamicroservices.productservice.dto.ProductCreatedDTO}
唯一的区别是消费者应用被称为库存服务而不是产品服务,因此它总是导致转换错误。
有什么解决办法吗?我当前的临时“解决方案”正在使用原语或 java.util 类,我稍后将其转换为目标类,但它远非理想,因为我有需要发送超过 8 种不同类型对象的情况,我用完了原语对于我的@RabbitHandler...
我还通过在生产者中定义目标类路径使其工作,但由于消息被发送到多个队列/服务,因此在这里不是一个可行的解决方案。
编辑:
这是我的配置:
事件制作人:
@Configuration
public class EventProducerConfiguration {
@Bean(name="productCreatedDeletedExchange")
public Exchange createdDeletedExchange() {
return new FanoutExchange("productCreatedDeletedExchange");
}
@Bean
public RabbitTemplate rabbitTemplate(final ConnectionFactory connectionFactory) {
final var rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMessageConverter(messageConverter());
return rabbitTemplate;
}
@Bean
public MessageConverter messageConverter() {
Jackson2JsonMessageConverter messageConverter = new Jackson2JsonMessageConverter();
DefaultClassMapper classMapper = new DefaultClassMapper();
classMapper.setTrustedPackages("*");
classMapper.setIdClassMapping(Map.of("created",ProductCreatedDTO.class));
messageConverter.setClassMapper(classMapper);
return messageConverter;
}
}
我如何发送消息:
rabbitTemplate.convertAndSend(deletedCreatedExchange.getName(),RoutingKeys.CREATED.getNotation(),new ProductCreatedDTO(p,brand.getId(),category.getId()));
事件消费者:
@Configuration
public class EventConsumerConfiguration {
@Bean(name="productsExchange")
public FanoutExchange productsPubSubExchange() {
return new FanoutExchange("productCreatedDeletedExchange");
}
@Bean
public Queue productsQueue() {
return new Queue("productsInventoryServiceQueue");
}
@Bean
public Binding bindingProducts(@Qualifier("productsExchange") FanoutExchange productsExchange) {
return BindingBuilder
.bind(productsQueue())
.to(productsExchange);
}
@Bean
public ProductOpsReceiver productEventsReceiver() {
return new ProductOpsReceiver();
}
}
Ps:我不确定是否需要像在生产者配置中所做的那样在消费者配置中使用消息转换器定义rabbitTemaplate,但是这两个应用程序既是消费者又是生产者,因此定义了这些bean尽管如此。
我如何接收消息:
@RabbitListener(queues="productsInventoryServiceQueue")
public class ProductOpsReceiver {
@RabbitHandler
public void productCreated(ProductCreatedDTO product) {
logger.info(PRODUCT_CREATED_LOG,product.getId());
}
}
解决方法
我想您正在使用 Jackson2JsonMessageConverter
。
您可以将类型映射添加到转换器的 typeMapper。
生产者方面
mapper.setIdClassMapping(Map.of(ProductCreatedDTO.class,"created"));
在消费者端,将目标类映射到相同的标记。
类型映射器将使用类型 ID 标头(在本例中为 created
)查询映射以确定要使用的类型。