声明式远程调用:OpenFeign 基础教程

远程调用(OpenFeign)

我没专门讲编程式的远程调用,可以自己看一下 RestTemplate ,这里就不多做赘述了

什么是OpenFeign?

  • 声明式HTTP客户端:通过接口+注解方式实现服务调用
  • 基于Ribbon的负载均衡:内置客户端负载均衡能力
  • 与Spring Cloud整合:无缝对接Eureka/Nacos等注册中心
  • 优势: ✅ 简化HTTP API调用 ✅ 支持多种编码器/解码器 ✅ 可插拔的注解支持

核心优势

特性 传统 RestTemplate OpenFeign
代码复杂度 需手动拼接 URL 和参数 接口声明直接映射远程 API
维护成本 修改 URL 需多处调整 集中管理接口定义
扩展性 需自定义拦截器 支持全局/局部拦截器配置

快速入门

  1. 添加依赖
xml 复制代码
<!-- OpenFeign 核心依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <version>4.1.2</version>
        </dependency>
  1. 启用OpenFeign
css 复制代码
在启动类上加`@EnableFeignClients`注解开启 Feign 远程调用功能
less 复制代码
@EnableFeignClients  // 关键注解:开启 Feign 客户端扫描
@EnableDiscoveryClient // 开启服务发现功能
@SpringBootApplication
public class ProductApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProductApplication.class, args);
    }
    
}
  1. 声明式接口定义

向第三方发送也是一样的,只要声明正确了(@FeignClient的url属性),feign 会帮忙发送

kotlin 复制代码
@FeignClient("small-order") // feign 客户端, 指定服务名(需注册到注册中心)
public interface OrderFeignClient {
​
    @GetMapping("/order/test") // 与远程接口完全一致
    String test();
​
}

我这里提前写好了一个测试用的服务接口,和 feign 不是同一个服务

其他类型的参数:

和springMVC使用相同的注解即可

less 复制代码
@GetMapping("/user/{id}")  
User getUserById(@PathVariable("id") Long userId);  // 必须指定参数名  
​
@PostMapping("/user/create")  
User createUser(@RequestBody UserDTO userDTO);  // 对象自动序列化为 JSON  
  1. 使用

    在我们的业务中注入刚才声明好的 feign 接口,注入到属性中即可使用,和 mybatis 类似,后续在访问此接口的时候,会使用feign完成远程调用

less 复制代码
@Slf4j
@RestController
public class TestController {
    @Autowired
    private OrderFeignClient orderFeignClient;
​
    @GetMapping("/test")
    public String test() {
        String test = orderFeignClient.test();
        log.info("使用 feign 远程调用 order 服务的test接口,返回数据:{}",test);
        return "test";
    }
}

可以在控制台看到日志记录,feign帮我们完成了远程调用

常见问题排查:

问题现象 解决方案
404 接口不存在 检查 @FeignClient 服务名是否与注册中心一致
参数传递失败 确保 @PathVariable 指定参数名
无法注入 Feign 客户端 确认主类添加了 @EnableFeignClients

进阶配置

  1. 日志追踪

springboot的配置文件

yaml 复制代码
logging:
  level:
    com.huang.small.feign: debug # 注意这是自己的包名
    

配置类:

kotlin 复制代码
@Configuration  
public class FeignConfig {  
    @Bean  
    Logger.Level feignLoggerLevel() {  
        return Logger.Level.FULL;  // 输出完整请求日志  正式环境不推荐使用,可以用来排错
    }  
}  
  1. 超时控制

我们这里通过一个场景来讲解一下为什么需要这个功能。

我们现在有两个服务,分别是订单服务和商品服务,我们生成一个商品的订单时,需要去向商品服务发送请求,获取到具体的商品数据如果商品服务的服务器宕机了,订单服务就一直无法连接到商品服务,或者说连接上了但是业务逻辑处理的太慢了,很久都无法活动响应数据,就会导致 openfeign 一致获取不到结果,就可能导致雪崩问题(这里不详细说明,简单理解一下就可以)。

简单来说,就是 openfeign 在发起远程调用的时候,设置一个超时时间,在超时时间内,就正常返回结果,如果超过了这个时间,就不等了,中断这次远程调用,这个时候 openfeign 有两种形式的返回:

  • 返回错误信息,提示我们远程服务超时
  • 返回兜底数据,比如默认为 0,没有库存(需要配合熔断框架)

对于超时控制,我们还需要了解两个配置:

  • connectTimeout: 连接超时(默认10s)
  • readTimeout: 读取超时 (默认60s)

可以通过配置来修改这两个配置:

yaml 复制代码
spring:
  application:
    name: small-product # 应用名称,会在 nacos 中显示
  cloud:
    openfeign:
      client:
        config:
          default: # 这个是默认配置,也可以像下面一样进行精确配置
            connect-timeout: 1000 # 连接超时时间 毫秒
            read-timeout: 3000 # 读取超时时间 毫秒
          small-product: # 你的feign客户端名字,可以在@FeignClient("small-order")这个注解中配置
            connect-timeout: 1000 # 连接超时时间 毫秒
            read-timeout: 3000 # 读取超时时间 毫秒
  1. 重试机制

远程调用失败后,还可以进行多次尝试,如果某次成功则返回ok,如果多次依然失败则结束调用,返回错误(默认不重试 )

在配置类中加入重试器的 bean :

typescript 复制代码
@Bean
Retryer retryer() {
    return new Retryer.Default(1000, 1000, 3);
}
  • period: 间隔多少毫秒(第一次间隔,后面每次的间隔是前一次的1.5倍)
  • maxPeriod: 最多间隔多少(每次超时重试的等待时间为 间隔 * 1.5 最多不超过这个参数的时长)
  • maxAttempts: 最多尝试几次
  1. 拦截器

请求拦截器: openfeign 在远程服务发送请求之前,由请求拦截器对请求进行一些定制化的修改,比如向请求头里面加入一些字段

响应拦截器: 远程服务处理完请求以后,把响应数据交给响应拦截器,对响应进行一个预处理,再把真正的结果发给 openfeign

因为响应拦截器用的比较少,所以我这里只给出请求拦截器的实例代码,响应拦截器也差不多,不过是换一个接口实现即可

定义一个类:实现 RequestInterceptor ,重写apply方法,需要使用@Component注解注入到容器中

typescript 复制代码
@Component
public class TestRequestInterceptor implements RequestInterceptor {
    /**
     * 请求拦截器
     * @param requestTemplate 这次请求的详细信息
     */
    @Override
    public void apply(RequestTemplate requestTemplate) {
        requestTemplate.header("test", "test");
    }
}

可以自己测试一下响应拦截器的用法

  1. Fallback(需要配合熔断框架才能实现)

返回兜底数据:

  • 创建一个类实现我们的 feign 客户端接口,并加上@Component注解,注册到容器中:
less 复制代码
@Slf4j
@Component
public class OrderFeignClientFallback implements OrderFeignClient {
    @Override
    public String test() {
        log.info("这是兜底回调.......");
        return "兜底数据";
    }
}

实现接口中的方法,这个方法将会作为兜底的执行方案

  • 在 feign 接口的注解写明对应的兜底的类

@FeignClient注解中的 fallback 就是用来兜底的类,请求失败之后会从容器中拿到这个类型的bean执行兜底回调

kotlin 复制代码
@FeignClient(value = "small-order",fallback = OrderFeignClientFallback.class) // feign 客户端
public interface OrderFeignClient {
​
    @GetMapping("/order/test")
    String test();
​
}
  • 整合熔断框架

只是为了可以看到效果,这里不会具体介绍熔断相关的知识

导入sentinel的依赖

xml 复制代码
<dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
      <version>2023.0.1.0</version>
</dependency>

添加配置

yaml 复制代码
feign:
  sentinel:
    enabled: true 
相关推荐
芒猿君15 分钟前
AQS——同步器框架之源
后端
SaebaRyo23 分钟前
手把手教你在网站中启用https和http2
后端·nginx·https
A-Kamen38 分钟前
Spring Boot拦截器(Interceptor)与过滤器(Filter)深度解析:区别、实现与实战指南
java·spring boot·后端
豆豆酱43 分钟前
Transformer结构详解
后端
upsilon44 分钟前
golang切片slice
后端·go
狂奔小菜鸡1 小时前
Java运行时数据区
java·jvm·后端
lovebugs1 小时前
Java并发编程之Lock机制:更灵活的线程同步方案
后端·面试
kunge20131 小时前
Paddle快速入门
后端
卑微小文1 小时前
2025国内网络反爬新高度:代理IP智能轮换算法揭秘
后端·算法·架构
ChinaRainbowSea1 小时前
MySQL 索引的数据结构(详细说明)
java·数据结构·数据库·后端·mysql