我遇到了这样一种情况:我需要为一个第三方 API 定义一个单独的 @FeignClient。在这个客户端中,我想使用一个与我的 @Primary ObjectMapper 不同的自定义 Jackson ObjectMapper。我知道可以覆盖 Spring 的 Feign 配置默认值,但是我不清楚如何仅针对这个特定的客户端简单地覆盖 ObjectMapper。
@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;
}
}
return new JacksonDecoder(customObjectMapper());
非常简单。 - leveluptor跟随@NewBie的答案,我可以提供更好的方案...
@Bean
public Decoder feignDecoder() {
return new JacksonDecoder();
}
<!-- feign-jackson decoder -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-jackson</artifactId>
<version>10.1.0</version>
</dependency>
new HttpMessageConverters
的过程中,将执行loadclass操作,导致大量线程阻塞。如果您使用了此代码,请按以下方式进行修改:
ObjectFactory<HttpMessageConverters> objectFactory = () -> new HttpMessageConverters(jacksonConverter);
改为
HttpMessageConverters httpMessageConverters = new HttpMessageConverters(jacksonConverter);
ObjectFactory<HttpMessageConverters> objectFactory = () -> httpMessageConverters;
您可以使用 JMeter 和 Arthas 来重现这个现象,并且修改过的程序已经得到了极大的改进。
如下定义一个自定义解码器,用@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);
};
}
}
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);
}
}
HttpMessageConverters
对象。按照正常的Spring Boot方式进行配置应该可以“正常工作”(虽然我自己没有尝试过)。http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#howto-customize-the-jackson-objectmapper - spencergibbSpringDecoder
bean,并在那里进行一些处理。 - spencergibb