在 Spring Cloud 体系中,可以使用 Feign 和 RestTemplate 两种方式实现服务间的 RPC 调用,它们底层使用相同的负载均衡组件 Ribbon。这篇文章主要介绍这两种调用方法及差异,有助于项目中进行技术选型。
概览
Ribbon
负载均衡本质是使用一定的算法从多个相同的服务中选择出一个合适的服务进行访问。Ribbon 便是一个负载均衡组件,它会从注册中心获取一组服务器地址列表,在发送请求前通过负载均衡算法选择一个服务器,然后进行访问。RestTemplate 和 Feign 都集成了 Ribbon, 不过集成的方式略有不同;
RestTemplate
为 RestTemplate 类添加 @LoadBalanced annotation, 便可在 RestTemplate 中添加对 Ribbon 的支持。
1 |
|
添加 @LoadBalanced annotation 之后,本质上向 RestTemplate 中添加了一个负载均衡拦截器 LoadBalancerInterceptor, 在该拦截器实现对 Ribbon 的引入。
1 | // LoadBalancerInterceptor |
RestTemplate 调用最终会被 Ribbon 接管,从而实现负载均衡的功能。
Feign
使用 Feign, 需要两步操作。
- 定义 Feing 接口
使用 FeignClient 定义一个接口,Feign 为其实现一个代理类,将其添加到 Spring 容器中。客户端使用 @Autowired 注入即可。
1 | (value = "provider-service") |
- 开启
EnableFeignClients
1 |
|
添加 EnableDiscoveryClient annotation 之后,它会扫描所有带 FeignClient annotation 的接口,并为其向 Spring 容器中注册一个 FeignClientFactoryBean 类,FeignClientFactoryBean 将返回 UserFeignClient 接口的代理类,在该代理类中将添加对 Ribbon 的支持。
1 |
|
至此,UserFeignClient 接口被实例化,并添加到 Spring 容器中,该接口的实现类集成了 Ribbon.
项目结构
在这里我们构建一个 Demo, 在该 Demo 中实现 Nacos 作为注册中心,相关版本如下所示:1
2
3
4
5<properties>
<spring-boot.version>2.2.5.RELEASE</spring-boot.version>
<spring-cloud.version>Hoxton.SR3</spring-cloud.version>
<spring-cloud-alibaba.version>2.2.1.RELEASE</spring-cloud-alibaba.version>
</properties>
工程整体结构如下:

- 使用 Nacos 作为注册中心;
- rpc-service-provider 作为服务提供方,将服务到 Nacos 中;
- rpc-restemplate-client, rpc-feign-client 作为客户端使用不同协议调用服务提供方。
工程代码
服务端
1、加入依赖
1 | <dependency> |
2、服务端实现
向外提供三个接口。
1 |
|
3、开启服务发现功能
通过 EnableDiscoveryClient annotation 引入服务发现功能。
1 |
|
4、加入配置1
2
3
4
5
6
7
8
9
10
11
12server:
port: 9501
spring:
application:
name: provider-service
cloud:
nacos:
discovery:
server-addr: 192.168.1.100:8848
username: nacos
password: nacos
RestTemplate 客户端
1、加入依赖
1 | <dependency> |
2、构造 RestTemplate
向 RestTemplate 中加入 Ribbon 负载均衡器。1
2
3
4
5
6
7
8
public class RestConfig {
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
3、客户端代码
使用 RestTemplate 发起 RPC, 只需要将服务器地址改为服务名称 provider-service 即可。
1 |
|
4、开启服务发现功能1
2
3
4
5
6
7
8
public class RestTemplateClientApp {
public static void main(String[] args) {
SpringApplication.run(RestTemplateClientApp.class, args);
}
}
5、加入配置1
2
3
4
5
6
7
8
9
10
11
12server:
port: 9092
spring:
application:
name: resttmplate-client
cloud:
nacos:
discovery:
server-addr: 192.168.1.100:8848
username: nacos
password: nacos
Feign 客户端
1、加入依赖1
2
3
4
5
6
7
8
9
10
11
12
13
14<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2、定义接口1
2
3
4
5
6
7
8
9
10
11
12(value = "provider-service")
public interface UserFeignClient {
(value = "/users/name")
String name();
("/users/online")
UserDTO currentUser();
("/users/query")
Result<UserDTO> query();
}
3、客户端代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
("/users")
public class UserController {
private UserFeignClient userFeignClient;
(value = "/name", method = RequestMethod.GET)
public String name() {
return userFeignClient.name();
}
("/online")
public UserDTO currentUser() {
return userFeignClient.currentUser();
}
("/query")
public Result<UserDTO> query() {
return userFeignClient.query();
}
}
4、开启服务发现及 FeignClient 功能
通过 EnableFeignClients annotation 扫描 FeignClient 接口,生成代理类。
1 |
|
5、加入配置1
2
3
4
5
6
7
8
9
10
11
12server:
port: 9093
spring:
application:
name: feign-client
cloud:
nacos:
discovery:
server-addr: 192.168.1.100:8848
username: nacos
password: nacos
总结
Feign 和 RestTemplate 两种方式以下面的特点:
RestTemplate只需要通过添加@LoadBalancedannotation 便可实现负载均衡的功能;RestTemplate的使用方式与常规的方式一样,只需要将服务地址改为服务名称即可;Feign需要申明客户端接口,通过代码生成技术实现代理类;RestTemplate使用简单,但对泛型的结果对象需要额外处理;- 从使用体验上来说,
Feign虽然额外定义一个接口,对于调用方而言,更为简单。
工程代码:https://github.com/noahsarkzhang-ts/springboot-lab/tree/main/springcloud-rpc
参考: