feign.RequestInterceptor 简介-笔记
1. feign.RequestInterceptor
简介
Feign 是一个声明式 Web 服务客户端,用于简化 HTTP 请求的编写与管理。feign.RequestInterceptor
是 Feign 提供的一个接口,用于在请求发出之前对其进行拦截和修改。这在微服务架构中非常有用,比如在请求中统一添加认证头、日志追踪标识、设置自定义头等,从而提升代码的可维护性和一致性。
RequestInterceptor
接口的核心方法是:
void apply(RequestTemplate template);
该方法会在每次 Feign 发起请求之前被调用。可以通过 RequestTemplate
对象修改请求的以下内容:
- 添加或修改请求头(Headers)
- 添加或修改请求参数(Query Parameters)
- 修改请求体(Body)
- 添加日志或追踪信息
- 添加身份验证信息(如 Token、OAuth 令牌等)
2. RequestInterceptor
使用示例
step1.创建 AuthRequestInterceptor。
该拦截器是一个简单的 RequestInterceptor
实现,用于在所有请求中添加认证 Token:
import feign.RequestInterceptor;
import feign.RequestTemplate;public class AuthRequestInterceptor implements RequestInterceptor {@Overridepublic void apply(RequestTemplate template) {// 添加认证 Token 到请求头template.header("Authorization", "Bearer your_access_token_here");}
}
step2. 将拦截器应用到 Feign Client
通过以下两种方式将 AuthRequestInterceptor
应用到你的 Feign Client 中:
方法一:通过 @FeignClient
注解配置
import org.springframework.cloud.openfeign.FeignClient;//注意:configuration 属性接受一个类或多个类,用于配置 Feign Client 的行为。
@FeignClient(name = "user-service",configuration = AuthRequestInterceptor.class
)
public interface UserClient {@GetMapping("/users/{id}")User getUser(@PathVariable("id") Long id);
}
方法二:通过配置类注册为 Bean
先在配置类中注册 RequestInterceptor
为 Bean:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class FeignConfig {@Beanpublic RequestInterceptor authRequestInterceptor() {return new AuthRequestInterceptor();}
}
再在 @FeignClient
中引用配置类:
@FeignClient(name = "user-service",configuration = FeignConfig.class
)
public interface UserClient {@GetMapping("/users/{id}")User getUser(@PathVariable("id") Long id);
}
3. 一个完整的示例
3.1 场景说明
在微服务架构中,使用 Feign 作为 HTTP 客户端时,我们常常需要对请求进行统一处理。这些需求可以通过多个 RequestInterceptor
实现,并在 Feign 请求发送前依次执行。下面我们通过一个实际场景来演示如何配置多个 RequestInterceptor
并使用它们。
我们有一个名为 order-service
的服务,它通过 Feign 调用 user-service
来获取用户信息。在调用过程中,我们需要:
- 添加认证 Token(如 JWT);
- 生成请求追踪 ID(用于链路追踪);
- 记录请求日志(便于调试与监控)。
3.2 项目结构
src/main/java
├── config
│ └── FeignConfig.java
├── interceptor
│ ├── AuthInterceptor.java
│ ├── TraceInterceptor.java
│ └── LoggingInterceptor.java
├── client
│ └── UserClient.java
└── Application.java
3.3 代码
step1. 定义多个 RequestInterceptor
AuthInterceptor: 添加认证信息
package com.example.interceptor;import feign.RequestInterceptor;
import feign.RequestTemplate;public class AuthInterceptor implements RequestInterceptor {@Overridepublic void apply(RequestTemplate template) {template.header("Authorization", "Bearer your_access_token");}
}
TraceInterceptor: 添加请求追踪 ID
package com.example.interceptor;import feign.RequestInterceptor;
import feign.RequestTemplate;
import java.util.UUID;public class TraceInterceptor implements RequestInterceptor {@Overridepublic void apply(RequestTemplate template) {String traceId = UUID.randomUUID().toString();template.header("X-Request-ID", traceId);}
}
LoggingInterceptor:记录请求日志
// LoggingInterceptor.java
package com.example.interceptor;import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class LoggingInterceptor implements RequestInterceptor {private static final Logger logger = LoggerFactory.getLogger(LoggingInterceptor.class);@Overridepublic void apply(RequestTemplate template) {logger.info("Sending request to: {}", template.url());logger.info("Method: {}, Headers: {}", template.method(), template.headers());}
}
step2.配置多个 RequestInterceptor
将多个拦截器注册为 Bean,并统一配置到 Feign Client 中:
package com.example.config;import com.example.interceptor.AuthInterceptor;
import com.example.interceptor.LogginInterceptor;
import com.example.interceptor.TraceInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class FeignConfig {@Beanpublic AuthInterceptor authInterceptor() {return new AuthInterceptor();}@Beanpublic TraceInterceptor traceInterceptor() {return new TraceInterceptor();}@Beanpublic LogginInterceptor loggingInterceptor() {return new LogginInterceptor();}
}
⚠️ 注意:Spring Boot 会自动将所有 RequestInterceptor
类型的 Bean 注册到 Feign 中,无需手动注入,只要 Feign Client 使用了对应的配置。
step3. Feign Client 使用配置
package com.example.client;import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;@FeignClient(name = "user-service",configuration = FeignConfig.class // 关键:引用配置类
)
public interface UserClient {@GetMapping("/users/{id}")String getUserById(@PathVariable("id") Long id);
}
当调用 userClient.getUserById(123)
时,控制台输出如下:
INFO LoggingInterceptor - Sending request to: http://user-service/users/123
INFO LoggingInterceptor - Method: GET, Headers: {Authorization=[Bearer your_access_token], X-Request-ID=[abc123...]}
拦截器执行顺序说明
Feign 默认按照 Bean 注册顺序执行 RequestInterceptor
。你可以通过 @Order
注解改变执行顺序,例如:
@Order(1)
public class AuthInterceptor implements RequestInterceptor { ... }@Order(2)
public class TraceInterceptor implements RequestInterceptor { ... }
3.4 其他用法
3.4.1 可以不使用@FeignClient
配置的做法
也可以将 FeignConfig
类集成到 Spring Boot 的自动配置类中,并通过 spring.factories
注册该自动配置类时
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.example.client. FeignConfig
这样就无需在 @FeignClient
中通过 configuration = FeignConfig.class
显式引用配置类。
原因:
-
自动配置机制的作用:Spring Boot 的自动配置机制通过
spring.factories
文件注册的类在应用启动时自动加载。只要FeignConfig
正确地注册了RequestInterceptor
等 Bean(如AuthInterceptor
、TraceInterceptor
、LoggingInterceptor
),这些 Bean 就会被 Spring 容器管理,并且 全局生效。 -
FeignClient 的默认行为:Feign Client 在创建时会自动查找 Spring 容器中所有
RequestInterceptor
类型的 Bean,并按照注册顺序依次应用。因此,只要这些拦截器被正确注册为 Spring Bean,就不需要通过@FeignClient(configuration = ...)
引用配置类。
3.4.2 何时仍需使用@FeignClient
配置
虽然大多数情况下不需要显式引用配置类,但在以下场景中仍可能需要使用 @FeignClient(configuration = FeignConfig.class)
:
-
自定义 Feign Client 的配置需求
- 如果某个 Feign Client 需要使用特定的配置类(比如不同的拦截器组合或覆盖默认配置),可以通过
configuration
属性指定。 - 例如,某个 Feign Client 只需要
AuthInterceptor
,而其他 Feign Client 需要AuthInterceptor + LoggingInterceptor
。
- 如果某个 Feign Client 需要使用特定的配置类(比如不同的拦截器组合或覆盖默认配置),可以通过
-
控制 Bean 加载顺序
- 如果拦截器的执行顺序非常重要,可以通过
@Order
注解或在配置类中显式控制顺序。 - 使用
@FeignClient(configuration = FeignConfig.class)
可以确保配置类中的 Bean 被优先加载。
- 如果拦截器的执行顺序非常重要,可以通过
-
避免自动配置与手动配置冲突
- 如果自动配置类和手动配置类中存在相同类型的 Bean(如多个
RequestInterceptor
实现),可能会导致冲突。此时可通过@FeignClient(configuration = ...)
显式指定。
- 如果自动配置类和手动配置类中存在相同类型的 Bean(如多个
3.4.3 总结
场景 | 是否需要 @FeignClient(configuration = FeignConfig.class) |
---|---|
FeignConfig 已通过自动配置类注册到 Spring 容器 | ❌ 不需要 |
某个 Feign Client 需要自定义拦截器组合 | ✅ 需要 |
需要控制拦截器的执行顺序 | ✅ 需要(结合 @Order 使用) |
避免自动配置与手动配置冲突 | ✅ 需要 |
实践建议
- 优先使用自动配置:如果所有 Feign Client 都需要相同的拦截器配置,直接通过自动配置类注册即可,无需每个 Feign Client 配置
configuration
。 - 确保自动配置类正确注册:检查
FeignConfig
是否已注册到 Spring 容器,并验证拦截器是否生效。 - 按需定制配置:如果某些 Feign Client 需要特殊处理,再通过
@FeignClient(configuration = ...)
显式指定。