Feign 学习笔记
#Feign#Java
2026年 3月 22日
微服务项目里服务间调用是个问题,RestTemplate 写起来太繁琐,Ribbon 还要自己处理负载均衡。Feign 把这些都封装好了,用起来像调用本地方法一样。
Feign 是什么
Feign 是 Netflix 开源的声明式 HTTP 客户端,后来 Spring Cloud 把它整合进去了。
说白了就是:你定义一个接口,加几个注解,Feign 帮你生成实现类,调用远程服务像调本地方法一样。
基本使用
依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency> 如果服务发现用的是 Nacos,还要加负载均衡依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency> 启用 Feign
启动类加注解:
@SpringBootApplication
@EnableFeignClients
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
} 定义 Feign Client
@FeignClient(name = "user-service")
public interface UserClient {
@GetMapping("/user/{id}")
User getUserById(@PathVariable("id") Long id);
@PostMapping("/user")
User createUser(@RequestBody User user);
} name 属性写目标服务的服务名,Feign 会自动去注册中心找。
调用
@Service
public class OrderService {
@Autowired
private UserClient userClient;
public Order createOrder(Long userId) {
User user = userClient.getUserById(userId);
// 业务逻辑...
return order;
}
} 就这么简单,不用管 HTTP 请求细节。
超时配置
默认超时时间有点短,生产环境要调整:
feign:
client:
config:
default:
connectTimeout: 5000
readTimeout: 5000
user-service:
connectTimeout: 10000
readTimeout: 10000 可以配置全局的 default,也可以针对某个服务单独配置。
日志配置
Feign 的日志级别:
NONE- 不记录(默认)BASIC- 只记录请求方法、URL、响应状态码和执行时间HEADERS- 记录 BASIC 级别的基础上,记录请求和响应的 headerFULL- 记录请求和响应的 header、body 和元数据
配置方式:
feign:
client:
config:
user-service:
loggerLevel: FULL 还要配置 Feign 的日志级别,因为 Feign 的日志是 DEBUG 级别:
@Configuration
public class FeignConfig {
@Bean
public Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
} application.yml 里也要加:
logging:
level:
com.example.client: debug 请求拦截器
比如要统一加 token:
@Configuration
public class FeignConfig {
@Bean
public RequestInterceptor requestInterceptor() {
return 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);
}
}
};
}
} 降级处理
配合 Sentinel 或 Hystrix 可以做降级:
@FeignClient(name = "user-service", fallback = UserClientFallback.class)
public interface UserClient {
@GetMapping("/user/{id}")
User getUserById(@PathVariable("id") Long id);
}
@Component
public class UserClientFallback implements UserClient {
@Override
public User getUserById(Long id) {
return new User(-1L, "默认用户", "default@example.com");
}
} 配置开启:
feign:
sentinel:
enabled: true 遇到的问题
调用 404 - 检查服务名对不对,路径对不对,目标服务是否注册成功。
超时问题 - 默认超时 1 秒,接口慢的话肯定超时,记得调整。
请求头丢失 - 异步调用时
RequestContextHolder拿不到,要手动传递。文件上传 - 要用
@RequestPart注解,还要配置编码器:
@FeignClient(name = "file-service", configuration = FileFeignConfig.class)
public interface FileClient {
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
String upload(@RequestPart("file") MultipartFile file);
} @Configuration
public class FileFeignConfig {
@Bean
public Encoder feignFormEncoder() {
return new SpringFormEncoder(new SpringEncoder(new ObjectFactory<HttpMessageConverters>() {
@Override
public HttpMessageConverters getObject() {
return new HttpMessageConverters(new RestTemplate().getMessageConverters());
}
}));
}
} 小结
Feign 确实方便,省了很多重复代码。不过底层还是 HTTP 调用,性能上不如 Dubbo 这种 RPC 框架。但对于大多数业务场景,Feign 够用了,开发效率也高。
后面打算试试 Feign 和 Sentinel 整合,做更完善的熔断降级。
