如何使用 Spring Cloud Netflix Feign 设置自定义 Jackson ObjectMapper

问题描述 投票:0回答:5

我遇到了一种情况,我需要为第三方 API 定义一次性 @FeignClient。在此客户端中,我想使用与我的 @Primary 不同的自定义 Jackson ObjectMapper。我知道可以覆盖 spring 的 feign 配置默认值,但是我不清楚如何仅通过此特定客户端来简单地覆盖 ObjectMapper。

spring spring-mvc spring-cloud feign spring-cloud-netflix
5个回答
46
投票

根据文档,您可以为 Feign 客户端提供自定义解码器,如下所示。

假客户端接口:

@FeignClient(value = "foo", configuration = FooClientConfig.class)
public interface FooClient{
    //Your mappings
}

Feign 客户端自定义配置:

@Configuration
public class FooClientConfig {

    @Bean
    public Decoder feignDecoder() {
        HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter(customObjectMapper());

        HttpMessageConverters httpMessageConverters = new HttpMessageConverters(jacksonConverter);
        ObjectFactory<HttpMessageConverters> objectFactory = () -> httpMessageConverters;


        return new ResponseEntityDecoder(new SpringDecoder(objectFactory));
    }

    public ObjectMapper customObjectMapper(){
        ObjectMapper objectMapper = new ObjectMapper();
        //Customize as much as you want
        return objectMapper;
    }
}

13
投票

按照@NewBie的答案,我可以给出更好的......

  @Bean
  public Decoder feignDecoder() {
    return new JacksonDecoder();
  }

如果您想在feign客户端中使用jackson消息转换器,请使用JacksonDecoder,因为SpringDecoder会增加feignclient调用的平均延迟在生产中

    <!-- feign-jackson decoder -->
    <dependency>
      <groupId>io.github.openfeign</groupId>
      <artifactId>feign-jackson</artifactId>
      <version>10.1.0</version>
    </dependency>

4
投票

@NewBie 的答案存在严重的性能问题。

new HttpMessageConverters
过程中会执行loadclass,导致大量线程阻塞。如果您使用过此代码,请修改如下:

ObjectFactory<HttpMessageConverters> objectFactory = () -> new HttpMessageConverters(jacksonConverter);

更改为

HttpMessageConverters httpMessageConverters = new HttpMessageConverters(jacksonConverter);
ObjectFactory<HttpMessageConverters> objectFactory = () -> httpMessageConverters;

可以使用JMeter和Arthas重现这个现象,修改后的程序有了很大的改进。


0
投票

定义一个自定义解码器如下,用

@Configuration
注释并设置为 feign 客户端接口的参数,
configuration = CustomFeignClientConfig.class

@Configuration
public class CustomFeignClientConfig {
    @Bean
    public Decoder feignDecoder() {
        return (response, type) -> {
            String bodyStr = Util.toString(response.body().asReader(Util.UTF_8));
            JavaType javaType = TypeFactory.defaultInstance().constructType(type);
            return new ObjectMapper().readValue( bodyStr, javaType);
        };
    }
}

0
投票
public SpringDecoder(ObjectFactory<HttpMessageConverters> messageConverters)

已弃用。你应该使用另一个构造函数:

public SpringDecoder(ObjectFactory<HttpMessageConverters> messageConverters,
            ObjectProvider<HttpMessageConverterCustomizer> customizers)

例如:

    @Bean
    public Decoder feignDecoder(ObjectProvider<HttpMessageConverterCustomizer> customizers) {
//        HttpMessageConverter<?> jacksonConverter = new MappingJackson2HttpMessageConverter(customObjectMapper());
//        HttpMessageConverters httpMessageConverters = new HttpMessageConverters(jacksonConverter);
        
        HttpMessageConverters httpMessageConverters = new HttpMessageConverters();
        return new ResponseEntityDecoder(new SpringDecoder(() -> httpMessageConverters, customizers));
    }

如果你想编写一个解码时间定制器,那么你可以这样写:

@Component
public class HttpMessageCustomizer implements HttpMessageConverterCustomizer {
    @Override
    public void accept(List<HttpMessageConverter<?>> httpMessageConverters) {
        //customizing
    }

    @Override
    public Consumer<List<HttpMessageConverter<?>>> andThen(Consumer<? super List<HttpMessageConverter<?>>> after) {
        return HttpMessageConverterCustomizer.super.andThen(after);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.