Feign 远程调用
一、Feign 概述
为什么需要 Feign
┌─────────────────────────────────────────────────────────────────┐
│ RestTemplate vs Feign │
├─────────────────────────────────────────────────────────────────┤
│ │
│ RestTemplate: │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ String url = "http://user-service/api/user/" + id; │ │
│ │ User user = restTemplate.getForObject(url, User.class);│ │
│ └─────────────────────────────────────────────────────────┘ │
│ 问题:URL 拼接麻烦、缺乏类型安全 │
│ │
│ Feign(声明式): │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ @FeignClient("user-service") │ │
│ │ public interface UserClient { │ │
│ │ @GetMapping("/api/user/{id}") │ │
│ │ User getUser(@PathVariable Long id); │ │
│ │ } │ │
│ └─────────────────────────────────────────────────────────┘ │
│ 优势:像调用本地方法一样调用远程服务 │
│ │
└─────────────────────────────────────────────────────────────────┘二、快速开始
Maven 依赖
xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>启用 Feign
java
@SpringBootApplication
@EnableFeignClients // 启用 Feign 客户端
public class OrderApplication { }定义客户端
java
@FeignClient(name = "user-service", url = "http://localhost:8080")
public interface UserClient {
@GetMapping("/api/user/{id}")
User getUser(@PathVariable("id") Long id);
@PostMapping("/api/user")
User createUser(@RequestBody User user);
@GetMapping("/api/user")
List<User> getUsers(@RequestParam("ids") List<Long> ids);
}使用
java
@Service
public class OrderService {
@Autowired
private UserClient userClient;
public Order getOrderWithUser(Long orderId) {
Order order = orderRepository.findById(orderId);
User user = userClient.getUser(order.getUserId());
order.setUser(user);
return order;
}
}三、负载均衡
集成 Ribbon
yaml
spring:
cloud:
openfeign:
client:
config:
default:
logger-level: full
user-service:
logger-level: basicjava
// Ribbon 自动生效(需要引入 spring-cloud-starter-ribbon)
@FeignClient(name = "user-service") // name = 服务名,从 Nacos 获取
public interface UserClient {
// 自动负载均衡
}负载均衡策略
yaml
user-service:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule # 轮询
# 其他策略:
# RandomRule # 随机
# WeightedResponseTimeRule # 权重
# BestAvailableRule # 最小连接数四、熔断与降级
Maven 依赖
xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-feign</artifactId>
</dependency>启用熔断
yaml
spring:
cloud:
openfeign:
circuitbreaker:
enabled: true定义降级
java
@Component
public class UserClientFallback implements UserClient {
@Override
public User getUser(Long id) {
return User.builder().id(id).name("默认用户").build();
}
@Override
public List<User> getUsers(List<Long> ids) {
return Collections.emptyList();
}
}
@FeignClient(name = "user-service", fallback = UserClientFallback.class)
public interface UserClient {
@GetMapping("/api/user/{id}")
User getUser(@PathVariable Long id);
}五、请求拦截器
自定义拦截器
java
@Component
public class FeignAuthInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate template) {
// 添加 Token
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null && auth.getCredentials() != null) {
template.header("Authorization", auth.getCredentials().toString());
}
// 添加租户 ID
template.header("X-Tenant-Id", TenantContext.getTenantId());
}
}日志拦截器
java
@Configuration
public class FeignLogConfig {
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL; // NONE/BASIC/HEADERS/FULL
}
}六、配置优化
超时配置
yaml
spring:
cloud:
openfeign:
client:
config:
default:
connect-timeout: 5000 # 连接超时
read-timeout: 10000 # 读取超时
user-service:
connect-timeout: 3000
read-timeout: 5000GZIP 压缩
yaml
spring:
cloud:
openfeign:
compression:
request:
enabled: true
response:
enabled: true七、面试高频问题
Q1: Feign 和 Ribbon 关系?
Feign 默认集成 Ribbon,实现负载均衡
Q2: Feign 如何实现熔断?
集成 CircuitBreaker,配置 fallback 类,失败时返回降级结果
Q3: @FeignClient 的 name 是什么?
服务名,会从 Nacos/Eureka 获取实例列表
八、下一章预告
下一章我们将学习 Sentinel 熔断限流:
- Sentinel 概述
- 流控规则
- 熔断策略
- Sentinel + Gateway