OpenFeign自定义Decoder,解析全局公共类判断status并返回data属性

需求出现

使用Feign调用服务接口返回公共类,使用时每次都需要判断status与获取data,十分冗余,可以使用一个自定义的解码器Decoder,在调用返回时对实体类进行统一判断status并获取data

331f7824ffba4c3590ad18bc19e6c84b.png

303cc35ff641455d8740e22e06520a31.png

fad1cdecc7c44cc587f6146ae4232a0b.png

最终实现

ce622645a4334aa3b8af4e4862887f24.png

思路与实现代码

自定义一个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);
    }
}

测试成功

05563ada9569439ea7f2d942dda3ad1c.png

研究过程

Feign的默认响应解码链:OptionalDecoder, ResponseEntityDecoder, SpringDecoder

响应首先来到OptionalDecoder的decode,response是feign提供的响应对象,type是要转为的目标类型(FeignClient定义的接口的返回/接收值)

ParameterizedType继承与Type,表示一个参数化类型,如List<String>Map<Integer, String>,它可用来描述类、接口或方法中的泛型信息,提供了方法来获取原始类型(raw type)和类型参数(type arguments)的信息

7cb149c77c9e44a1bc245ef04446e45a.png

进入ResponseEntityDecoder的decode

97c11719eaaf460da01911587ab45637.png

最后来到的SpringDecoder的decode,在这里将Response对象及解析返回最终的type类型的java对象

f8a0dfe21c354278a83b12a6f2c998bf.png

SpringDecoder的decode大致过程(简单了解)

  1. 判断目标类型合法的
  2. 利用Spring框架的消息转换器messageConverters来执行这个任务,并可以通过自定义器来customizers自定义转换器的行为
  3. 创建一个HttpMessageConverterExtractor对象,最终通过调用该对象的extractData方法将Feign的响应Response对象转化为Java对象

 以上本人的代码实现:替换ResponseEntityDecoder的下一个解码器为我们自定义的Decoder

2de13d55f13743d08b12c53406f0d914.png

利用SpringDecoder解析response解析为type目标类型,需要的参数我们可以模仿ResponseEntityDecoder

首先需要知道ResponseEntityDecoder为了调用SpringDecoder的decode,需要传递的参数为response和ApiRestResponse为原类型的ParameterizedTypeImpl对象

看向ResponseEntityDecoder.decode方法

正常情况下的参数type

T为包含泛型的类(如List,Map)

26a31131d9dd435fa5ae8c0de812b2c8.png

08e02ea56c3e4ee78f7be4e680a431c8.png

 T为普通类(UserVo)

77912e6c3f79476d8cd5e35263006e90.png

122338a290ed42e0821d66a563fe81d6.png

 查看完毕

不使用ApiRestResponse的情况下的type

c79130bac86449479ea853dc9cfbcee3.png

 36ba88f6897d441682cb20d1831fb223.png

将type封装为上面有ApiRestResponse的类即可在我们自定义的Decoder中调用SpringDecoder的功能

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菠萝追雪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值