跳到主要内容

快速入门

本章将带你从零开始搭建一个完整的 OpenFeign 项目,通过实际操作理解其核心用法。

环境准备

版本要求

OpenFeign 的版本与 Spring Cloud 版本紧密相关,需要确保版本兼容:

Spring Cloud 版本Spring Boot 版本OpenFeign 版本
2024.0.x3.4.x4.x
2023.0.x3.2.x, 3.3.x4.x
2022.0.x3.0.x, 3.1.x4.x
版本选择建议

新项目建议使用最新的稳定版本。Spring Cloud 2024.0.x 基于 Spring Boot 3.4.x,包含最新的特性和安全更新。

创建项目

使用 Spring Initializr 创建一个 Spring Boot 项目,添加以下依赖:

Maven 配置:

<properties>
<java.version>17</java.version>
<spring-cloud.version>2024.0.0</spring-cloud.version>
</properties>

<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- Spring Cloud OpenFeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

<!-- 可选:负载均衡支持 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
</dependencies>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

Gradle 配置:

ext {
springCloudVersion = '2024.0.0'
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
implementation 'org.springframework.cloud:spring-cloud-starter-loadbalancer'
}

dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}

启用 Feign 客户端

在启动类上添加 @EnableFeignClients 注解,启用 Feign 客户端功能:

@SpringBootApplication
@EnableFeignClients
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

@EnableFeignClients 注解有几个重要的属性:

@EnableFeignClients(
basePackages = "com.example.clients", // 扫描 Feign 客户端的包路径
clients = {UserClient.class, OrderClient.class} // 显式指定客户端类
)
扫描范围

如果不指定 basePackages,默认只扫描启动类所在包及其子包。建议显式指定包路径,避免因包结构问题导致 Feign 客户端无法被扫描到。

创建第一个 Feign 客户端

定义客户端接口

创建一个接口,使用 @FeignClient 注解标记:

@FeignClient(name = "user-service", url = "https://jsonplaceholder.typicode.com")
public interface UserClient {

@GetMapping("/users")
List<User> getAllUsers();

@GetMapping("/users/{id}")
User getUserById(@PathVariable("id") Long id);

@PostMapping("/users")
User createUser(@RequestBody User user);

@PutMapping("/users/{id}")
User updateUser(@PathVariable("id") Long id, @RequestBody User user);

@DeleteMapping("/users/{id}")
void deleteUser(@PathVariable("id") Long id);
}

@FeignClient 注解的属性说明:

属性说明是否必填
name / value客户端名称,用于服务发现时的服务标识
url直接指定的服务地址,支持占位符
configuration自定义配置类
fallback降级处理类
fallbackFactory降级工厂类,可获取异常信息
path统一请求路径前缀
primary是否标记为首选 Bean,默认 true

定义数据模型

创建与 API 响应对应的数据模型:

public class User {
private Long id;
private String name;
private String username;
private String email;
private String phone;
private String website;

// 构造方法、getter、setter 省略
}

使用 Feign 客户端

在服务类中注入 Feign 客户端,像调用本地方法一样使用:

@Service
public class UserService {

private final UserClient userClient;

public UserService(UserClient userClient) {
this.userClient = userClient;
}

public List<User> getAllUsers() {
return userClient.getAllUsers();
}

public User getUserById(Long id) {
return userClient.getUserById(id);
}

public User createUser(User user) {
return userClient.createUser(user);
}
}

创建一个控制器来测试:

@RestController
@RequestMapping("/api/users")
public class UserController {

private final UserService userService;

public UserController(UserService userService) {
this.userService = userService;
}

@GetMapping
public List<User> getAllUsers() {
return userService.getAllUsers();
}

@GetMapping("/{id}")
public User getUserById(@PathVariable Long id) {
return userService.getUserById(id);
}

@PostMapping
public User createUser(@RequestBody User user) {
return userService.createUser(user);
}
}

配置文件设置

application.yml 中添加基本配置:

spring:
application:
name: feign-demo
cloud:
openfeign:
client:
config:
default: # 全局默认配置
connectTimeout: 5000 # 连接超时(毫秒)
readTimeout: 5000 # 读取超时(毫秒)
loggerLevel: basic # 日志级别
user-service: # 特定客户端配置
connectTimeout: 3000
readTimeout: 10000

# 启用 Feign 日志
logging:
level:
com.example.clients: DEBUG

运行测试

启动应用后,访问以下端点测试:

# 获取所有用户
curl http://localhost:8080/api/users

# 获取单个用户
curl http://localhost:8080/api/users/1

# 创建用户
curl -X POST http://localhost:8080/api/users \
-H "Content-Type: application/json" \
-d '{"name":"Test User","username":"testuser","email":"[email protected]"}'

与服务发现集成

在实际的微服务环境中,通常会使用服务发现组件(如 Nacos、Eureka)。此时不需要指定 url,Feign 会自动从注册中心获取服务实例:

// 不指定 url,通过服务发现获取实例
@FeignClient(name = "user-service")
public interface UserClient {
@GetMapping("/users/{id}")
User getUserById(@PathVariable("id") Long id);
}

添加 Nacos 依赖:

<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

配置 Nacos 地址:

spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848

常见问题排查

Feign 客户端注入失败

问题:启动时报错 No qualifying bean of type 'UserClient'

原因:Feign 客户端接口未被扫描到

解决方案

  1. 检查 @EnableFeignClients 的扫描路径是否包含客户端接口所在包
  2. 确保客户端接口使用了 @FeignClient 注解
  3. 检查包结构是否正确
// 方案一:指定包路径
@EnableFeignClients(basePackages = "com.example.clients")

// 方案二:显式指定客户端类
@EnableFeignClients(clients = UserClient.class)

连接超时

问题:请求时报错 ConnectTimeout

原因:连接超时时间设置过短或目标服务不可用

解决方案

spring:
cloud:
openfeign:
client:
config:
default:
connectTimeout: 10000 # 增加连接超时时间
readTimeout: 30000 # 增加读取超时时间

序列化/反序列化失败

问题:报错 JSON parse errorCould not extract response

原因:返回的 JSON 与 Java 对象不匹配

解决方案

  1. 检查 Java 对象的字段名是否与 JSON 字段名一致
  2. 使用 @JsonProperty 注解映射字段名
  3. 检查日期格式是否正确
public class User {
@JsonProperty("user_id") // JSON 字段名为 user_id
private Long id;

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
}

小结

本章我们完成了:

  1. 搭建了一个完整的 OpenFeign 项目
  2. 创建了第一个 Feign 客户端接口
  3. 实现了基本的 CRUD 操作
  4. 了解了与服务发现组件的集成方式
  5. 掌握了常见问题的排查方法

下一章将深入学习 OpenFeign 的注解体系,掌握如何定义各种类型的 HTTP 请求。