之前有一篇文章(OpenFeign 自定义结果转换)介绍了怎么自定义解析OpenFein的返回结果。之后再使用中发现,在接口正常的情况下。都能按照我们自定义的情况展示。
但是在现实应用中我们可能要经过很多次代理。每个代理的错误返回都可能存在不一样的情况。这就会导致之前的转换出问题。而且很多时候我们只需要部分接口做转换,而不是所有的接口做转换,也有可能是需要处理某一种 OpenFein没有实现的 contentType的转换方式。
基于以上问题,所以我想,如果能在原有的OpenFein的解析方式中增加自定义的解析方式。例如假如 我的content-type=json/1231231 是 就用自定义的解析方式。至于其他的已有类型就用OpenFein默认的转换解析方式。
通过查看资料和研究OpenFein的解析源码。我们可以知道,OpenFeign的结果解析转换是依赖于Decoder类的decode()方法。
在FeignClientsConfiguration可以找到OpenFeign的解析注入方式:
@Configuration(proxyBeanMethods = false)
public class FeignClientsConfiguration {
@Autowired
private ObjectFactory messageConverters;
//..... 忽略代码
/**
*
*这是注入解析接口返回的转换的方法
*/
@Bean
@ConditionalOnMissingBean
public Decoder feignDecoder(ObjectProvider customizers) {
return new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(messageConverters, customizers)));
}
/**
*
*这是注入解析接口请求的转换的方法
*/
@Bean
@ConditionalOnMissingBean
@ConditionalOnMissingClass("org.springframework.data.domain.Pageable")
public Encoder feignEncoder(ObjectProvider formWriterProvider,
ObjectProvider customizers) {
return springEncoder(formWriterProvider, encoderProperties, customizers);
}
//...忽略代码
}
查看OptionalDecoder源码可以知道:
import feign.Response;
import feign.Util;
import feign.codec.Decoder;
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Objects;
import java.util.Optional;
public final class OptionalDecoder implements Decoder {
final Decoder delegate;
public OptionalDecoder(Decoder delegate) {
Objects.requireNonNull(delegate, "Decoder must not be null. ");
this.delegate = delegate;
}
@Override
public Object decode(Response response, Type type) throws IOException {
if (!isOptional(type)) {
//这里调用了默认的解析方式
return delegate.decode(response, type);
}
if (response.status() == 404 || response.status() == 204) {
return Optional.empty();
}
Type enclosedType = Util.resolveLastTypeParameter(type, Optional.class);
return Optional.ofNullable(delegate.decode(response, enclosedType));
}
static boolean isOptional(Type type) {
if (!(type instanceof ParameterizedType)) {
return false;
}
ParameterizedType parameterizedType = (ParameterizedType) type;
return parameterizedType.getRawType().equals(Optional.class);
}
}
参照 OptionalDecoder 我们可以实现自己的 结果解析器。在Content-Type为指定类型时,使用我们自己的解析器,其他则继续调用默认的解析转换:
public class FeignResultDecoder implements Decoder {
private static final Logger LOGGER = LoggerFactory.getLogger(FeignResultDecoder.class);
final Decoder delegate;
public FeignResultDecoder(Decoder delegate) {
Objects.requireNonNull(delegate, "Decoder must not be null. ");
this.delegate = delegate;
}
@Override
public Object decode(Response response, Type type) throws IOException, DecodeException, FeignException {
if (response.body() != null && response.headers().get("Content-Type").contains("json/text;charset=UTF-8")) {
String bodyStr = Util.toString(response.body().asReader(Util.UTF_8));
if (StringUtils.isNotEmpty(bodyStr)) {
//对结果进行转换
try {
JavaType javaType = TypeFactory.defaultInstance().constructType(type);
return new ObjectMapper().readValue(bodyStr, javaType);
} catch (IOException e) {
LOGGER.error("将JSON转换为对象时发生错误,url :{}, 数据:{}", response.request().url(), bodyStr);
throw new IllegalArgumentException("将JSON转换为对象时发生错误" , e);
}
} else {
LOGGER.error("feign结果返回为空, url:{}, status:{}", response.request().url(), response.status());
}
}
//这里和可以加入其他的自定义类型扩展实现
else {
return delegate.decode(response, type);
}
return null;
}
}
config配置: 对所有配置生效
@Configuration
public class ExternalMvcConfig {
@Autowired
private ObjectFactory messageConverters;
@Bean
public Decoder feignDecoder(ObjectProvider customizers) {
return new FeignResultDecoder(new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(messageConverters, customizers))));
}
}
通过以上的方式就可以在原有的解析方法上加入自定义的解析方式了