Spring-cloud-openfeign解码器Decoder接口(后置拦截器)

使用feign调用第三方的http服务,对方返回response,之后这个Decoder接口会将对方的返回值,序列化成我们的返回值,例如下面的代码中,为什么我们能拿到User类型,而不是一个String类型,这就是Decoder来处理的

cpp 复制代码
@FeignClient(name = "xxx", url = "xxx")
public interface UserAPI {

	// 即使对方返回一个符合json格式的String类型,feign也能将这个String转换成User,这就是Decoder接口做的事情
    @GetMapping(value = "/xxx/xxx")
    User getUser(@RequestParam("userId") Integer userId);
    
}

下面的代码自定义了一个Decoder,由于Decoder是用来解析对方返回值,所以我这里使用Decoder来打印日志,这样省的每个接口自己打印对方返回值了

步骤1:自定义一个解码器

cpp 复制代码
package 你的包名

import feign.Response;
import feign.codec.Decoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
/**
 * <p>这个类本质上是个第三方Http Response的解码器,本类主要目的是在解码的同时打印日志
 *
 * @author shiwentian
 * @since 1.7.2024
 **/
public class OpenFeignPostInterceptor implements Decoder {

    private static final Logger log = LoggerFactory.getLogger(OpenFeignPostInterceptor.class);

    private final Decoder delegate;

    public OpenFeignPostInterceptor(Decoder delegate) {
        this.delegate = delegate;
    }

    @Override
    public Object decode(Response response, Type type) throws IOException {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int bytesRead;
        while ((bytesRead = response.body().asInputStream().read(buffer)) != -1) {
            byteArrayOutputStream.write(buffer, 0, bytesRead);
        }
        byte[] body = byteArrayOutputStream.toByteArray();
        String bodyStr = new String(body, StandardCharsets.UTF_8);
        log.info("调用第三方接口返回:{}", bodyStr);
        return delegate.decode(response.toBuilder().body(bodyStr, StandardCharsets.UTF_8).build(), type);
    }
}

步骤2:将上面自定义的解码器通过lite的注入方式,注入到spring容器

cpp 复制代码
package 你的包名;

import feign.codec.Decoder;
import feign.optionals.OptionalDecoder;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.support.ResponseEntityDecoder;
import org.springframework.cloud.openfeign.support.SpringDecoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 本类用于注册自定义的解码器
 *
 * @author shiwentian
 * @since 1.7.2024
 **/
@Configuration
public class DecoderConfig {

	// 这个地方需要注意,不能使用@Resource,涉及到泛型问题,如果没有泛型,那么使用@Resource是可以的
    @Autowired
    private ObjectFactory<HttpMessageConverters> messageConverters;

    @Bean
    public Decoder decode() {
        return new OpenFeignPostInterceptor(new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(this.messageConverters))));
    }
}

好了,现在启动服务,通过feign调用第三方服务,会发现对方每次返回,都会打印对方的返回值

注意:我没有测试对方服务失败的情况,或者一些其他失败的情况,所以本文中的response.body().asInputStream()这段代码可能会出现不健壮的情况,需要你自己对失败的情况进行处理

源代码参考:Spring Cloud Open Feign 2.2.9版本org.springframework.cloud.openfeign.FeignClientsConfiguration类的public Decoder feignDecoder() 方法

相关推荐
myzshare1 天前
实战分享:我是如何用SSM框架开发出一个完整项目的
java·mysql·spring cloud·微信小程序
sww_10261 天前
Openfeign源码浅析
java·spring cloud
DKunYu1 天前
9.熔断和限流 - Alibaba Sentinel
spring cloud·微服务·sentinel
麦兜*1 天前
【springboot】图文详解Spring Boot自动配置原理:为什么@SpringBootApplication是核心?
android·java·spring boot·spring·spring cloud·tomcat
kaico20182 天前
远程调用组件openfeign
java·spring cloud
独自归家的兔2 天前
Spring Cloud核心架构组件深度解析(原理+实战+面试高频)
spring cloud·面试·架构
麦兜*3 天前
【Spring Boot】 接口性能优化“十板斧”:从数据库连接到 JVM 调优的全链路提升
java·大数据·数据库·spring boot·后端·spring cloud·性能优化
码农小卡拉3 天前
Springboot “钩子”:@PostConstruct注解
java·spring boot·后端·spring·spring cloud
qq_12498707533 天前
基于SpringCloud的分布式演唱会抢票系统(源码+论文+部署+安装)
分布式·spring·spring cloud·毕业设计·计算机毕业设计
元Y亨H3 天前
微服务架构核心组件、职责与交互全解析
spring cloud