【问题标题】:Spring Boot trusted packages for rabbitmqrabbitmq 的 Spring Boot 可信包
【发布时间】:2019-01-15 08:31:30
【问题描述】:

我们正在构建一个通过 RabbitMQ 接收消息的 Spring Boot 应用程序 (2.0.4-RELEASE)。因此application.properties 包含了兔子相关的配置:

spring.rabbitmq.addresses=****
spring.rabbitmq.username=****
spring.rabbitmq.password=****
spring.rabbitmq.listener.simple.concurrency=2
spring.rabbitmq.listener.simple.prefetch=5
spring.rabbitmq.listener.simple.retry.enabled=true
spring.rabbitmq.listener.simple.retry.max-attempts=5

配置:

@Bean
public TopicExchange fileUpdate() {
    return new TopicExchange("my.fancy.exchange", true, false);
}

@Bean
public Queue fileUpload() {
    return new Queue("myFancyQueue", true);
}

@Bean
public Binding bindingUpload(Queue queue, TopicExchange eventExchange) {
    return BindingBuilder.bind(queue).to(eventExchange).with("");
}

消息消费者:

@RabbitListener(queues = "myFancyQueue")
public void receive(Object message) {
    ...
}

当接收到特定类型的消息(例如__TypeId__: my.fancy.package.Clazz)时,会抛出以下错误:

原因:java.lang.IllegalArgumentException:类 'my.fancy.package.Clazz' 不是 在受信任的包中:[java.util, java.lang]。如果你相信这个 类可以安全反序列化,请提供其名称。如果 序列化仅由受信任的来源完成,您也可以启用 信任所有 (*)。

从我目前发现的情况来看,activeMQ 通过application.properties as 提供了一个配置选项

spring.activemq.packages.trust-all=

spring.activemq.packages.trusted=

但我找不到任何适用于 rabbitMQ 的类似选项。到目前为止,我一直在使用一种解决方法来解决我的问题,但当然最好在配置文件中有这样的选项。

到目前为止我的解决方案:

添加到配置类:

@Bean
public MessageConverter jsonMessageConverter() {
    Jackson2JsonMessageConverter jsonMessageConverter = new Jackson2JsonMessageConverter(new ObjectMapper());
    jsonMessageConverter.setClassMapper(new ImporterClassMapper(FileUploadMessage.class));        
    return jsonMessageConverter;
}

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

并将消息消费者更改为

@Resource(name = "jsonMessageConverter")
private MessageConverter messageConverter;

@RabbitListener(queues = "${uploaded.files.queue}")
public void receive(Message message) {
    FileUploadMessage uploadMessage = (FileUploadMessage) messageConverter.fromMessage(message);
    ...
}

另外添加了一个类映射器,它允许导入未知类型并设置一个默认类型,在导入时应该将消息转换为该类型:

public class ImporterClassMapper implements ClassMapper, InitializingBean {

    private volatile Class<?> defaultType;

    public ImporterClassMapper(Class<?> defaultType) {
        this.defaultType = defaultType;
    }    

    @Override
    public void afterPropertiesSet() throws Exception {
        // nothing to do
    }

    @Override
    public void fromClass(Class<?> clazz, MessageProperties properties) {
        // avoid setting __TypeId__ header so consumers from other modules can implement their own DTOs
    }

    @Override
    public Class<?> toClass(MessageProperties properties) {
        return this.defaultType;
    }

    public void setClass(Class<?> type) {
        this.defaultType = type;
    }
}

关于如何改进此解决方案的任何建议?

【问题讨论】:

  • 我认为使用 JSON 发送/接收任意类型是推荐的方法...
  • 是的,当然类型是在 JSON 中传输的。然而,他们提供了一个 TypeId。然后,DefaultClassMapper 将始终尝试将 JSON 转换为类型,并在使用者不知道类型时抛出异常

标签: java spring spring-boot rabbitmq


【解决方案1】:

我通过在正在使用的 Spring AMQP ClassMapper 上设置受信任的包来修复相同的错误。

@Configuration
public class RabbitConfig {

    @Bean
    @Scope("prototype")
    public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(SimpleRabbitListenerContainerFactory factory, ObjectMapper objectMapper) {
        factory.setMessageConverter(jsonToMapMessageConverter(objectMapper));
        return factory;
    }

    @Bean
    public MessageConverter jsonToMapMessageConverter(ObjectMapper objectMapper) {
        Jackson2JsonMessageConverter messageConverter = new ImplicitJsonMessageConverter(objectMapper);
        DefaultClassMapper classMapper = new DefaultClassMapper();
        classMapper.setTrustedPackages("*");
        classMapper.setDefaultType(Map.class);
        messageConverter.setClassMapper(classMapper);
        return messageConverter;
    }

    public static class ImplicitJsonMessageConverter extends Jackson2JsonMessageConverter {    
        public ImplicitJsonMessageConverter(ObjectMapper jsonObjectMapper) {
            super(jsonObjectMapper, "*");
        }    
        @Override
        public Object fromMessage(Message message) throws MessageConversionException {
            message.getMessageProperties().setContentType("application/json");
            return super.fromMessage(message);
        }
    }
}

【讨论】:

  • 虽然我花了一段时间 - 是的,这是一个更好的方法。让我无法实现自定义类映射器。谢谢
猜你喜欢
  • 1970-01-01
  • 2020-04-18
  • 1970-01-01
  • 2017-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-23
相关资源
最近更新 更多