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() 方法

相关推荐
椰椰椰耶15 小时前
[SpringCloud][11] Nacos 负载均衡,服务下线、权重配置、同集群优先访问
java·spring cloud·负载均衡
接着奏乐接着舞15 小时前
spring cloud RabbitMQ
spring·spring cloud·rabbitmq
Devin~Y15 小时前
从Spring Boot到AI Agent:大厂Java微服务面试三轮实战问答解析
java·spring boot·redis·spring cloud·微服务·ai·kafka
jasnet_u16 小时前
SpringCloud中服务集成PlumeLog日志系统
spring·spring cloud·plumelog·日志收集
linweidong16 小时前
Java 后端开发面试 50 个高频易混淆知识点详解
java·spring boot·spring·spring cloud·面试·mybatis·spring事务
JAVA社区1 天前
Java高级全套教程(十三)—— 分布式锁超详细实战详解(原理+三种方案企业级落地)
java·开发语言·分布式·spring cloud·面试·java-zookeeper
Devin~Y2 天前
智慧物流+AIGC客服Java大厂面试:Spring Boot、Kafka、Redis、JVM与RAG Agent实战
java·jvm·spring boot·redis·spring cloud·kafka·rag
worilb2 天前
Spring Cloud 学习与实践(4):订单服务开发
spring cloud
椰椰椰耶3 天前
[SpringCloud][12]Nacos配置中心详解,快速上手,Nacos和Eureka的区别
spring·spring cloud·eureka
半旧夜夏3 天前
【保姆级】微服务组件环境搭建(Docker Compose版)
java·linux·spring cloud·微服务·云原生·容器