在 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 | "provider-service") (value = |
- 开启
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"provider-service") (value =
public interface UserFeignClient {
"/users/name") (value =
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;
"/name", method = RequestMethod.GET) (value =
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
只需要通过添加@LoadBalanced
annotation 便可实现负载均衡的功能;RestTemplate
的使用方式与常规的方式一样,只需要将服务地址改为服务名称即可;Feign
需要申明客户端接口,通过代码生成技术实现代理类;RestTemplate
使用简单,但对泛型的结果对象需要额外处理;- 从使用体验上来说,
Feign
虽然额外定义一个接口,对于调用方而言,更为简单。
工程代码:https://github.com/noahsarkzhang-ts/springboot-lab/tree/main/springcloud-rpc
参考: