Spring MVC 如何使用Spring Cloud Netflix Feign设置自定义JacksonObjectMapper

jq6vz3qz  于 2023-10-24  发布在  Spring
关注(0)|答案(5)|浏览(161)

我遇到了一个场景,我需要为第三方API定义一个一次性的@FeignClient。在这个客户端中,我想使用一个与我的@Primary不同的自定义JacksonObjectMapper。我知道可以覆盖spring的feign配置默认值,但我不清楚如何简单地覆盖ObjectMapper。

pbwdgjma

pbwdgjma1#

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

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

伪装客户端自定义配置:

@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;
    }
}
mbzjlibv

mbzjlibv2#

按照@NewBie的回答,我可以给你更好的给予.

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

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

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

1dkrff033#

@NewBie的回答存在严重的性能问题,在new HttpMessageConverters进程中会执行loadclass,导致大量线程阻塞,如果你用过这段代码,请修改如下:

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

改变

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

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

8oomwypt

8oomwypt4#

如下定义一个自定义解码器,使用@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);
        };
    }
}
jucafojl

jucafojl5#

你可以使用SpringDecoder和SpringEncoder。

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);
        
        var httpMessageConverters = new HttpMessageConverters();
        return new ResponseEntityDecoder(new SpringDecoder(() -> httpMessageConverters, customizers));
    }

    @Bean
    public Encoder feignEncoder() {
        var httpMessageConverters = new HttpMessageConverters();
        return new SpringEncoder(() -> httpMessageConverters);
    }

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

@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);
    }
}

相关问题