(1) 概念速览(一句话总结)
-
RestTemplate :Spring 提供的传统同步 HTTP 客户端,基于
HttpMessageConverter,通过编程方式封装 HTTP 请求(GET/POST/PUT...)。适合灵活、手动控制请求细节的场景。 -
Feign(在 Spring Cloud 中通常为 Spring Cloud OpenFeign):声明式的 HTTP 客户端,通过接口 + 注解描述远程服务,底层会帮你生成实现并处理负载均衡、序列化、拦截器等。适合微服务间调用、代码更声明式、更简洁可读。
额外提醒:Spring 团队更推荐在新项目中使用 WebClient (响应式、非阻塞),而不是继续新建大量
RestTemplate(RestTemplate在很多场景已不再主动演进)。
(2) 原理/工作方式的关键差别
-
调用方式
-
RestTemplate:编程式 ,你写代码构造 URL、请求头/体、调用
getForObject/exchange等方法。 -
Feign:声明式 ,定义接口 + 注解(
@FeignClient、@RequestMapping),框架自动生成代理并实现 HTTP 调用。
-
-
集成微服务能力
-
Feign 与 Spring Cloud 集成时能自动配合负载均衡(Spring Cloud LoadBalancer)、服务发现(Eureka/Consul)、拦截器/解码器/编码器、请求重试和熔断/降级(与 Resilience4j/Hystrix 结合)。
-
RestTemplate 可用
RestTemplate+ 自己配置LoadBalancerClient或使用@LoadBalanced注入(配合 Spring Cloud LoadBalancer),但很多集成需要手动配置。
-
-
扩展点
-
RestTemplate:通过
ClientHttpRequestInterceptor、ResponseErrorHandler、HttpMessageConverter等自定义。 -
Feign:通过自定义
Encoder/Decoder、Contract、RequestInterceptor、ErrorDecoder、自定义Feign.Builder等扩展点。
-
-
风格
-
RestTemplate 更"原始/底层" → 适合灵活控制细节。
-
Feign 更"高层/声明式" → 代码简洁、接口即文档、更接近 RPC 风格。
-
(3) 常见用法对比(代码示例)
3.1 RestTemplate 示例(同步调用)
java
// Bean 配置(Spring Boot 推荐用 RestTemplateBuilder)
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder
.setConnectTimeout(Duration.ofSeconds(3))
.setReadTimeout(Duration.ofSeconds(5))
.build();
}
// 使用
@Service
public class UserService {
private final RestTemplate restTemplate;
public UserService(RestTemplate restTemplate) { this.restTemplate = restTemplate; }
public User getUserById(Long id) {
String url = "http://users-service/api/users/{id}";
ResponseEntity<User> resp = restTemplate.getForEntity(url, User.class, id);
if (resp.getStatusCode().is2xxSuccessful()) return resp.getBody();
throw new RuntimeException("调用失败: " + resp.getStatusCode());
}
public void createUser(User user) {
String url = "http://users-service/api/users";
HttpEntity<User> request = new HttpEntity<>(user);
restTemplate.postForEntity(url, request, Void.class);
}
}
如果需要服务发现 + 负载均衡(Spring Cloud),可以用:
java
// 注入 @LoadBalanced RestTemplate(会解析 serviceId)
@Bean
@LoadBalanced
public RestTemplate loadBalancedRestTemplate(RestTemplateBuilder builder) {
return builder.build();
}
3.2 Feign 示例(声明式)
java
// 引入依赖:spring-cloud-starter-openfeign
// 启用 Feign 客户端(主类上)
@EnableFeignClients
@SpringBootApplication
public class App { ... }
// 定义接口
@FeignClient(name = "users-service", path = "/api/users")
public interface UserFeignClient {
@GetMapping("/{id}")
User getUserById(@PathVariable("id") Long id);
@PostMapping
void createUser(User user);
}
// 使用
@Service
public class UserService {
private final UserFeignClient client;
public UserService(UserFeignClient client) { this.client = client; }
public User getUser(Long id) { return client.getUserById(id); }
}
Feign 客户端会自动处理 serviceId 到实例的负载均衡(与 Spring Cloud LoadBalancer 集成)。
(4) 常见扩展/高级点(实用技巧)
RestTemplate
-
设置拦截器:
ClientHttpRequestInterceptor用来添加鉴权 header、日志等。 -
错误处理:实现
ResponseErrorHandler,统一处理非 2xx 响应。 -
序列化:通过
MappingJackson2HttpMessageConverter自定义ObjectMapper。
Feign
-
请求拦截器:实现
RequestInterceptor添加 header(例如传递认证或跟踪 id)。 -
错误处理:实现
ErrorDecoder映射 HTTP 错误到异常。 -
日志:Feign 自带日志级别
Logger.Level,并可使用Slf4jLogger。 -
fallback:结合 Resilience(Resilience4j 或旧 Hystrix)支持降级。
-
自定义编码器/解码器:Feign 的
Encoder/Decoder允许更改请求体/响应反序列化逻辑。 -
复杂请求体/文件上传:Feign 的表单/上传需额外配置
Multipart支持或使用Feign Form扩展。
(5) 优缺点对比(实践角度)
Feign 优点
-
开发效率高:只写接口,代码短、可读性强,接口就是契约(像 RPC)。
-
与 Spring Cloud 集成好:服务发现、负载均衡、熔断/降级等集成更顺畅。
-
配置化扩展点多(logger、interceptor、error decoder)。
-
易于测试:接口可以 mock。
Feign 缺点
-
对复杂/动态请求(动态 URL、复杂 header 操作、流式响应)不如 RestTemplate 灵活。
-
默认同步阻塞;异步需要额外适配。
-
某些高级使用需要了解 Feign 的扩展(Encoder/Decoder)。
RestTemplate 优点
-
灵活、底层控制精细,适合需要手工构造请求的场景(流、文件、复杂 header)。
-
API 直观(更接近原生 HTTP 客户端),便于 debug。
RestTemplate 缺点
-
代码更样板化(频繁手写 URL、exchange、HttpEntity)。
-
与 Spring Cloud 高级特性(fallback、契约)集成不如 Feign 自然。
-
现代趋势是非阻塞 WebClient,RestTemplate 在新项目中不是首选。
(6) 常见问题 & 解决办法
-
如何传递请求头(比如 tracing / token)?
-
RestTemplate:在
HttpEntity中设置HttpHeaders或用ClientHttpRequestInterceptor。 -
Feign:实现
RequestInterceptor,或通过@RequestHeader在方法参数上声明。
-
-
如何处理 4xx/5xx?
-
RestTemplate:自定义
ResponseErrorHandler。 -
Feign:实现
ErrorDecoder,抛出业务异常或映射 HTTP code。
-
-
如何做重试/限流/熔断?
-
Feign:配合 Resilience4j(或 Hystrix 老方案)做熔断/重试/限流,Spring Cloud 提供集成。
-
RestTemplate:需要在调用端或调用链路中添加相应的拦截器/代理(例如 AOP + Resilience4j)。
-
-
日志如何打开?
-
Feign:设置
feign.logger.level=FULL并配置Logger。 -
RestTemplate:使用
ClientHttpRequestInterceptor或 HTTP 客户端(OkHttp/Apache)自身的日志。
-
(7) 什么时候选 Feign / RestTemplate / WebClient(实践选型建议)
-
首选 Feign:你在微服务架构中需要大量服务间同步调用,追求快速开发、声明式契约、并且想利用 Spring Cloud 的自动化(服务发现 + 负载均衡 + 熔断)。
-
选 RestTemplate:需要对单次 HTTP 请求做复杂定制(例如流式处理、文件上传/下载、动态 URL 生成),或项目已经大量使用 RestTemplate 且迁移成本高。
-
推荐 WebClient(Spring WebFlux):需要高并发、非阻塞 IO、响应式编程。新项目若对吞吐/并发有严格要求优先考虑 WebClient。
(8) 从 RestTemplate 迁移到 Feign(简易对照)
RestTemplate 代码:
java
User user = restTemplate.getForObject("http://users-service/api/users/{id}", User.class, id);
Feign 代码:
java
@FeignClient("users-service")
interface UserClient {
@GetMapping("/api/users/{id}")
User getUser(@PathVariable("id") Long id);
}
迁移步骤:
-
添加
spring-cloud-starter-openfeign依赖并启用@EnableFeignClients。 -
为每个远程服务创建 Feign 接口(保持路径/参数对应)。
-
将调用点改为注入 Feign 接口。
-
配置
RequestInterceptor、ErrorDecoder、日志等,保证行为一致(例如超时、认证头)。 -
单元测试改为 Mock Feign 接口。
(9) 小结 + 实战建议(Checklist)
-
如果你希望"接口就是客户端实现"、开发快、集成方便 → 用 Feign。
-
如果你需要"细粒度控制请求"、处理复杂 HTTP 场景 → 用 RestTemplate(或考虑用 HttpClient/OkHttp 做底层)。
-
如果系统需要高并发、响应式 → 用 WebClient。
-
在 Feign 中务必配置:超时、重试策略、ErrorDecoder、日志级别、认证拦截器(RequestInterceptor)。
-
在 RestTemplate 中务必配置:连接/读超时、
ResponseErrorHandler、合适的HttpMessageConverter。