OpenFeign #
一、OpenFeign概述 #
1.1 什么是OpenFeign #
OpenFeign是Spring Cloud提供的一个声明式HTTP客户端,使得编写Web服务客户端变得更加简单。只需创建一个接口并添加注解,即可完成服务调用。
text
┌─────────────────────────────────────────────────────────────┐
│ OpenFeign架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Feign Client 接口 │ │
│ │ │ │
│ │ @FeignClient("user-service") │ │
│ │ interface UserClient { │ │
│ │ @GetMapping("/users/{id}") │ │
│ │ User getUser(@PathVariable Long id); │ │
│ │ } │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Feign 核心组件 │ │
│ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌────────────┐ │ │
│ │ │ Encoder │ │ Decoder │ │ Contract │ │ │
│ │ │ 编码器 │ │ 解码器 │ │ 契约 │ │ │
│ │ └─────────────┘ └─────────────┘ └────────────┘ │ │
│ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌────────────┐ │ │
│ │ │ Client │ │ Logger │ │ Retryer │ │ │
│ │ │ HTTP客户端 │ │ 日志记录 │ │ 重试器 │ │ │
│ │ └─────────────┘ └─────────────┘ └────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
1.2 OpenFeign vs RestTemplate #
| 特性 | OpenFeign | RestTemplate |
|---|---|---|
| 编程方式 | 声明式 | 命令式 |
| 代码量 | 少 | 多 |
| 可读性 | 高 | 中 |
| 维护性 | 高 | 中 |
| 集成度 | 高 | 中 |
1.3 OpenFeign特性 #
| 特性 | 说明 |
|---|---|
| 声明式调用 | 接口+注解完成调用 |
| 负载均衡 | 集成LoadBalancer |
| 熔断降级 | 集成Circuit Breaker |
| 压缩支持 | 支持请求/响应压缩 |
| 日志记录 | 多级别日志记录 |
二、基本使用 #
2.1 添加依赖 #
xml
<dependencies>
<!-- OpenFeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- LoadBalancer -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
</dependencies>
2.2 启用Feign #
java
@SpringBootApplication
@EnableFeignClients
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
2.3 定义Feign客户端 #
java
@FeignClient("user-service")
public interface UserClient {
@GetMapping("/users/{id}")
User getUserById(@PathVariable("id") Long id);
@GetMapping("/users")
List<User> getAllUsers();
@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);
}
2.4 使用Feign客户端 #
java
@Service
public class UserService {
@Autowired
private UserClient userClient;
public User getUser(Long id) {
return userClient.getUserById(id);
}
public List<User> getAllUsers() {
return userClient.getAllUsers();
}
public User createUser(User user) {
return userClient.createUser(user);
}
}
三、参数传递 #
3.1 URL参数 #
java
@FeignClient("user-service")
public interface UserClient {
@GetMapping("/users/{id}")
User getUserById(@PathVariable("id") Long id);
@GetMapping("/users/{userId}/orders/{orderId}")
Order getUserOrder(
@PathVariable("userId") Long userId,
@PathVariable("orderId") Long orderId
);
}
3.2 查询参数 #
java
@FeignClient("user-service")
public interface UserClient {
@GetMapping("/users")
List<User> getUsersByName(@RequestParam("name") String name);
@GetMapping("/users/search")
Page<User> searchUsers(
@RequestParam("name") String name,
@RequestParam("page") int page,
@RequestParam("size") int size
);
}
3.3 请求体 #
java
@FeignClient("user-service")
public interface UserClient {
@PostMapping("/users")
User createUser(@RequestBody User user);
@PostMapping("/users/batch")
List<User> createUsers(@RequestBody List<User> users);
}
3.4 请求头 #
java
@FeignClient("user-service")
public interface UserClient {
@GetMapping("/users/{id}")
User getUserWithHeader(
@PathVariable("id") Long id,
@RequestHeader("Authorization") String token
);
@GetMapping("/users/info")
User getUserInfo(
@RequestHeader("X-Request-Id") String requestId,
@RequestHeader("X-User-Id") Long userId
);
}
3.5 表单提交 #
java
@FeignClient("user-service")
public interface UserClient {
@PostMapping(value = "/login", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
User login(
@RequestParam("username") String username,
@RequestParam("password") String password
);
}
四、配置详解 #
4.1 全局配置 #
yaml
feign:
client:
config:
default:
connectTimeout: 5000
readTimeout: 10000
loggerLevel: BASIC
4.2 单服务配置 #
yaml
feign:
client:
config:
user-service:
connectTimeout: 5000
readTimeout: 10000
loggerLevel: FULL
4.3 代码配置 #
java
@Configuration
public class FeignConfig {
@Bean
public Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
@Bean
public Request.Options requestOptions() {
return new Request.Options(5000, 10000);
}
@Bean
public Retryer retryer() {
return new Retryer.Default(100, 1000, 3);
}
}
4.4 应用配置 #
java
@FeignClient(name = "user-service", configuration = FeignConfig.class)
public interface UserClient {
// ...
}
五、日志配置 #
5.1 日志级别 #
| 级别 | 说明 |
|---|---|
| NONE | 无日志(默认) |
| BASIC | 请求方法、URL、响应状态码、执行时间 |
| HEADERS | BASIC + 请求头和响应头 |
| FULL | HEADERS + 请求体和响应体 |
5.2 配置日志 #
yaml
logging:
level:
com.example.client.UserClient: DEBUG
feign:
client:
config:
user-service:
loggerLevel: FULL
5.3 自定义日志 #
java
@Bean
public Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
六、熔断降级 #
6.1 添加依赖 #
xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
6.2 开启熔断 #
yaml
feign:
circuitbreaker:
enabled: true
6.3 定义降级类 #
java
@Component
public class UserClientFallback implements UserClient {
@Override
public User getUserById(Long id) {
User user = new User();
user.setId(id);
user.setName("默认用户");
return user;
}
@Override
public List<User> getAllUsers() {
return Collections.emptyList();
}
@Override
public User createUser(User user) {
return null;
}
}
6.4 配置降级 #
java
@FeignClient(
name = "user-service",
fallback = UserClientFallback.class
)
public interface UserClient {
// ...
}
6.5 降级工厂 #
java
@Component
public class UserClientFallbackFactory implements FallbackFactory<UserClient> {
@Override
public UserClient create(Throwable cause) {
return new UserClient() {
@Override
public User getUserById(Long id) {
System.out.println("Fallback reason: " + cause.getMessage());
User user = new User();
user.setId(id);
user.setName("降级用户");
return user;
}
@Override
public List<User> getAllUsers() {
return Collections.emptyList();
}
@Override
public User createUser(User user) {
return null;
}
};
}
}
java
@FeignClient(
name = "user-service",
fallbackFactory = UserClientFallbackFactory.class
)
public interface UserClient {
// ...
}
七、请求拦截器 #
7.1 自定义拦截器 #
java
public class AuthRequestInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate template) {
ServletRequestAttributes attributes = (ServletRequestAttributes)
RequestContextHolder.getRequestAttributes();
if (attributes != null) {
HttpServletRequest request = attributes.getRequest();
String token = request.getHeader("Authorization");
if (token != null) {
template.header("Authorization", token);
}
}
}
}
7.2 注册拦截器 #
java
@Configuration
public class FeignConfig {
@Bean
public RequestInterceptor authRequestInterceptor() {
return new AuthRequestInterceptor();
}
}
7.3 日志拦截器 #
java
public class LoggingRequestInterceptor implements RequestInterceptor {
private static final Logger log = LoggerFactory.getLogger(LoggingRequestInterceptor.class);
@Override
public void apply(RequestTemplate template) {
log.info("Feign Request: {} {}", template.method(), template.url());
log.info("Headers: {}", template.headers());
if (template.body() != null) {
log.info("Body: {}", new String(template.body()));
}
}
}
八、压缩配置 #
8.1 开启压缩 #
yaml
feign:
compression:
request:
enabled: true
mime-types: text/xml,application/xml,application/json
min-request-size: 2048
response:
enabled: true
九、超时重试 #
9.1 配置超时 #
yaml
feign:
client:
config:
default:
connectTimeout: 5000
readTimeout: 10000
9.2 配置重试 #
java
@Bean
public Retryer retryer() {
return new Retryer.Default(
100,
1000,
3
);
}
9.3 禁用重试 #
java
@Bean
public Retryer retryer() {
return Retryer.NEVER_RETRY;
}
十、继承支持 #
10.1 定义公共接口 #
java
public interface UserServiceApi {
@GetMapping("/users/{id}")
User getUserById(@PathVariable("id") Long id);
@GetMapping("/users")
List<User> getAllUsers();
@PostMapping("/users")
User createUser(@RequestBody User user);
}
10.2 服务端实现 #
java
@RestController
public class UserController implements UserServiceApi {
@Override
public User getUserById(Long id) {
return userService.findById(id);
}
@Override
public List<User> getAllUsers() {
return userService.findAll();
}
@Override
public User createUser(User user) {
return userService.save(user);
}
}
10.3 客户端继承 #
java
@FeignClient("user-service")
public interface UserClient extends UserServiceApi {
}
十一、最佳实践 #
11.1 统一配置 #
java
@Configuration
public class FeignGlobalConfig {
@Bean
public Logger.Level feignLoggerLevel() {
return Logger.Level.BASIC;
}
@Bean
public Request.Options requestOptions() {
return new Request.Options(5000, 10000);
}
@Bean
public RequestInterceptor authInterceptor() {
return new AuthRequestInterceptor();
}
}
11.2 统一响应处理 #
java
public class Result<T> {
private int code;
private String message;
private T data;
}
@Configuration
public class FeignConfig {
@Bean
public Decoder feignDecoder() {
return new ResponseEntityDecoder(new SpringDecoder(new SpringEncoderDecoderFactory().createMessageConverters()));
}
}
11.3 注意事项 #
| 注意点 | 说明 |
|---|---|
| 接口定义 | 不要在接口中定义无关方法 |
| 超时配置 | 合理设置连接和读取超时 |
| 熔断降级 | 关键服务必须配置降级 |
| 日志级别 | 生产环境使用BASIC级别 |
十二、总结 #
12.1 核心要点 #
| 要点 | 说明 |
|---|---|
| 声明式调用 | 接口+注解完成服务调用 |
| 参数传递 | @PathVariable、@RequestParam、@RequestBody |
| 熔断降级 | fallback/fallbackFactory |
| 拦截器 | RequestInterceptor统一处理 |
| 日志配置 | 多级别日志记录 |
12.2 下一步 #
现在你已经掌握了OpenFeign的使用,接下来让我们学习 负载均衡,了解Spring Cloud LoadBalancer的工作原理!
最后更新:2026-03-28