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