# 04.微服务-openFeign
# 1.介绍
# 1.1 什么是 OpenFeign?
OpenFeign 是一个声明式的 HTTP 客户端框架,最初由 Netflix 开发,后成为 Spring Cloud 生态的核心组件
核心理念:通过接口 + 注解的方式定义远程服务调用,将底层 HTTP 通信细节交给框架处理,开发者只需关注"做什么",而非"如何做"
# 1.2 Feign vs OpenFeign
| 对比项 | Feign | OpenFeign |
|---|---|---|
| 注解支持 | 仅支持 Feign 原生注解 | 支持 Spring MVC 注解(@RequestMapping、@GetMapping 等) |
| 框架集成 | 独立组件 | 深度集成 Spring Cloud,支持 Ribbon 负载均衡、服务发现等 |
📌 选型建议:Spring Cloud 项目中直接使用 OpenFeign。
# 1.3 核心注解
① @FeignClient:标注在接口上,声明这是一个 Feign 客户端。
| 属性 | 说明 | 示例 |
|---|---|---|
name / value | 目标服务名(注册中心中的服务 ID),配合 Ribbon 实现负载均衡 | @FeignClient(name = "order-service") |
url | 直接指定服务 URL(用于调试或非注册中心场景) | @FeignClient(url = "http://localhost:8081") |
path | 统一请求前缀 | @FeignClient(path = "/api/v1") |
configuration | 指定该客户端的专用配置类 | @FeignClient(configuration = FooConfig.class) |
fallback | 熔断降级类(需实现该接口) | @FeignClient(fallback = MyFallback.class) |
fallbackFactory | 熔断工厂类,可获取异常原因 | @FeignClient(fallbackFactory = MyFactory.class) |
② @EnableFeignClients:标注在启动类上,开启 Feign 客户端扫描和代理生成
# 2.快速使用
# 2.1引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2
3
4
# 2.2启动类开启Feign
@SpringBootApplication
@EnableFeignClients // 开启 Feign 客户端
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
2
3
4
5
6
7
# 2.3定义Feign接口
@Component
@FeignClient(value = "stock-service",path = "/stock")
public interface StockFeignService {
@RequestMapping("/deduct")
String deduct();
}
2
3
4
5
6
# 2.4使用
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private StockFeignService stockFeignService;
@RequestMapping("/add")
public String add(){
System.out.println("下单成功");
String msg = stockFeignService.deduct();
return "hello feign"+msg;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
# 2.5 参数传递方式
| 场景 | 注解 | 示例 |
|---|---|---|
| URL 路径参数 | @PathVariable | @GetMapping("/{id}") @PathVariable Long id |
| JSON 请求体 | @RequestBody | @PostMapping("/create") @RequestBody Order order |
| 表单/Query 参数 | @SpringQueryMap | @GetMapping("/search") @SpringQueryMap Params params |
# 3.日志配置
# 3.1 日志级别
| 级别 | 记录内容 |
|---|---|
NONE | 不记录任何日志(默认) |
BASIC | 请求方法、URL、响应状态码、执行时间 |
HEADERS | BASIC + 请求和响应的 Header 信息 |
FULL | HEADERS + 请求和响应的 Body 及元数据 |
# 3.2 配置方式
先设置springboot的日志级别(默认是info),info情况下feign的debug日志级别不会输入
logging:
level:
# 格式:包名.接口名: DEBUG
com.xy.order.feign.StockFeignService: DEBUG
2
3
4
方式一:Java Config(推荐)
@Configuration
public class FeignLogConfig {
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL; // 设置为 FULL 级别
}
}
2
3
4
5
6
7
8
@FeignClient注解中配置设置好的日志级别
@FeignClient(value = "stock-service",path = "/stock",configuration = FeignLogConfig.class)
方式二:配置文件 application.yml
spring:
application:
name: order-service
cloud:
openfeign:
client:
config:
stock-service:
logger-level: full
2
3
4
5
6
7
8
9
# 3.3 全局 vs 局部配置
全局生效:配置类使用
@Configuration注解,被组件扫描到仅对指定服务生效:配置类不加
@Configuration,通过@FeignClient(configuration = FeignLogConfig.class)指定
⚠️ 注意:日志级别需配合
logging.level.接口路径: DEBUG才会实际输出
# 4.超时时间
# 4.1 核心参数
| 参数 | 含义 | 默认值 |
|---|---|---|
connectTimeout | 建立连接的超时时间(毫秒) | 10 秒 |
readTimeout | 读取数据的超时时间(毫秒) | 60 秒 |
# 4.2 配置方式
方式一:配置文件(推荐)
spring:
application:
name: order-service
cloud:
openfeign:
client:
config:
stock-service:
logger-level: full
connect-timeout: 3000
read-timeout: 5000
2
3
4
5
6
7
8
9
10
11
方式二:Java Config
@Configuration
public class TimeoutConfig {
@Bean
public Request.Options options() {
// 连接超时 1 秒,读取超时 3 秒
return new Request.Options(1000, 3000);
}
}
2
3
4
5
6
7
8
9
# 5.自定义拦截器
# 5.1 核心接口
实现 RequestInterceptor 接口,重写 apply(RequestTemplate template) 方法
原理:Spring 容器自动扫描所有 RequestInterceptor Bean,在每次 Feign 请求发出前调用其 apply 方法,向 RequestTemplate 注入 Header 或其他参数
# 5.2 典型应用场景
| 场景 | 说明 |
|---|---|
| 认证透传 | 将 JWT / OAuth2 Token 自动传递到下游服务 |
| 链路追踪 | 自动生成并传递 TraceId / SpanId |
| 灰度标记 | 携带 X-Env: gray 等标识实现灰度路由 |
| 多语言/本地化 | 自动传递 Accept-Language |
# 5.3 代码示例
① 创建拦截器类
@Component
public class FeignAuthInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate template) {
// 从 ThreadLocal / SecurityContext 获取 Token
String token = UserContextHolder.getToken();
if (StringUtils.hasText(token)) {
template.header("Authorization", "Bearer " + token);
}
// 传递链路追踪 ID(可选)
String traceId = MDC.get("traceId");
if (traceId != null) {
template.header("X-Trace-Id", traceId);
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 5.4 注册拦截器
将拦截器声明为 Spring Bean 即可自动生效
@Configuration
public class FeignInterceptorConfig {
@Bean
public RequestInterceptor getRequestInterceptor() {
return new FeignAuthInterceptor(); // 或 new FeignRequestInterceptor()
}
}
2
3
4
5
6
7
8
over