需求出现
使用Feign调用服务接口返回公共类,使用时每次都需要判断status与获取data,十分冗余,可以使用一个自定义的解码器Decoder,在调用返回时对实体类进行统一判断status并获取data
最终实现
思路与实现代码
自定义一个Decoder实现类,将其设置为ResponseEntityDecoder的decoder,利用SpringDecoder解析response为目标对象,判断状态+返回公共类中的泛型对象
自定义Decoder
public class FeignResponseDecoder implements Decoder {
private final SpringDecoder springDecoder;
public FeignResponseDecoder(SpringDecoder springDecoder){
this.springDecoder = springDecoder;
}
@Override
public Object decode(Response response, Type type) throws IOException, DecodeException, FeignException {
Type orginalType = null;
if(type instanceof ParameterizedType){
// T是泛型如List<> Map<>,会被封装为ParameterizedTypeImpl
orginalType = ParameterizedTypeImpl.make(ApiRestResponse.class,new Type[]{type},null);
}else {
// T是Class类型
orginalType = ParameterizedTypeImpl.make(ApiRestResponse.class,new Type[]{type},null);
}
ApiRestResponse<?> result = (ApiRestResponse<?>) springDecoder.decode(response,orginalType);
if(result.getStatus() != ApiRestResponse.getOkCode()){
throw new DecodeException(response.status(), "接口返回错误:"+response.reason() , response.request());
}
return result.getData();
}
}
配置到容器中
@Configuration
public class OpenFeignConfig {
@Bean
public Decoder feignDecoder(ObjectFactory<HttpMessageConverters> msgConverters,
ObjectProvider<HttpMessageConverterCustomizer> customizers) {
// 自定义feign的解析器
// OptionalDecoder(response,type) -> ResponseEntityDecoder(response,type) -> 自定义Decoder(response,type)
FeignResponseDecoder feignResponseDecoder = new FeignResponseDecoder(
new SpringDecoder(msgConverters,customizers));
ResponseEntityDecoder responseEntityDecoder = new ResponseEntityDecoder(feignResponseDecoder);
return new OptionalDecoder(responseEntityDecoder);
}
}
测试成功
研究过程
Feign的默认响应解码链:OptionalDecoder, ResponseEntityDecoder, SpringDecoder
响应首先来到OptionalDecoder的decode,response是feign提供的响应对象,type是要转为的目标类型(FeignClient定义的接口的返回/接收值)
ParameterizedType继承与Type,
表示一个参数化类型,如List<String>
或Map<Integer, String>,它可
用来描述类、接口或方法中的泛型信息,提供了方法来获取原始类型(raw type)和类型参数(type arguments)的信息
进入ResponseEntityDecoder的decode
最后来到的SpringDecoder的decode,在这里将Response对象及解析返回最终的type类型的java对象
SpringDecoder的decode大致过程(简单了解)
- 判断目标类型合法的
- 利用Spring框架的消息转换器messageConverters来执行这个任务,并可以通过自定义器来customizers自定义转换器的行为
- 创建一个HttpMessageConverterExtractor对象,最终通过调用该对象的extractData方法将Feign的响应Response对象转化为Java对象
以上本人的代码实现:替换ResponseEntityDecoder的下一个解码器为我们自定义的Decoder
利用SpringDecoder解析response解析为type目标类型,需要的参数我们可以模仿ResponseEntityDecoder
首先需要知道ResponseEntityDecoder为了调用SpringDecoder的decode,需要传递的参数为response和ApiRestResponse为原类型的ParameterizedTypeImpl对象
看向ResponseEntityDecoder.decode方法
正常情况下的参数type
T为包含泛型的类(如List,Map)
T为普通类(UserVo)
查看完毕
不使用ApiRestResponse的情况下的type
将type封装为上面有ApiRestResponse的类即可在我们自定义的Decoder中调用SpringDecoder的功能