1 引言
在微服务架构中,服务之间的远程调用(RPC)((Remote Produce Call))是核心功能之一。本文将详细介绍RPC中的OpenFeign。
2 RPC是什么,什么时候用到?
在单体应用时代,所有代码都在一个项目里,函数调用都是本地的,非常简单。 但随着业务发展,单体应用变得越来越臃肿,难以维护和扩展。 😩 于是,微服务架构应运而生。 🚀
微服务架构将一个大型应用拆分成多个小的、独立的服务。 这些服务可能运行在不同的服务器上,使用不同的编程语言。 这时候,服务之间就需要相互通信才能完成业务逻辑。 🤝
常见的服务调用选择是使用 HTTP API。服务 A 通过 HTTP 请求调用服务 B 的 API。这种方式简单易懂,但存在一些问题:
- 效率较低: HTTP 协议相对比较重,传输的数据量大,解析也比较耗时。
- 灵活性差: HTTP API 通常需要定义明确的接口和数据格式,不够灵活。
- 难以管理: 当服务数量增多时,API 的管理和维护变得困难。
RPC 的作用就体现出来了:
- 解耦: 让服务之间独立运行,互不干扰。 一个服务的修改不会影响到其他服务。 🔗✂️
- 提高可扩展性: 可以根据业务需求,独立地扩展某个服务。 ⬆️
- 技术异构: 允许不同的服务使用不同的编程语言和技术栈。 🌐
- 简化开发: 开发者可以专注于自己的服务逻辑,而不用关心底层通信细节。 ✨
RPC(Remote Procedure Call)是一种远程过程调用协议,它允许一个程序调用另一个程序中的函数或方法,而无需了解底层的网络细节。因此RPC的出现使得分布式系统中的各个组件之间的通信变得更加简单、高效和可靠。
并且RPC协议提供了更加丰富和灵活的功能,例如支持不同的序列化格式、支持异步调用、支持自定义的错误处理等等(**如:gRPC、Apache Thrift、CORBA…等),而平常普通的http请求等就很难实现。因此在为了需要自定义上述的的功能,亦或者在分布式系统中需要进行组件的通信时,就需要rpc。(但是这里RPC底层的传输协议其实是可以用HTTP协议的,这种方式被称为HTTP-RPC或者HTTP-based RPC。在这种方式中,HTTP协议被用来传输RPC请求和响应数据。)
举个例子:
假设你有一个电商网站,拆分成以下几个微服务:
- 用户服务: 负责用户注册、登录等。 👤
- 商品服务: 负责商品信息的管理。 📦
- 订单服务: 负责处理订单的创建、支付等。 🛒
当用户下单时,订单服务需要调用用户服务来验证用户信息,调用商品服务来获取商品信息。 如果没有 RPC,你需要自己编写复杂的网络通信代码来实现这些调用。 😫 有了 RPC,你只需要像调用本地函数一样,调用用户服务和商品服务的接口即可。 😊
3 RPC 能帮助我们什么?
- 屏蔽底层通信细节: 开发者不用关心网络协议、序列化、反序列化等复杂细节,专注于业务逻辑。 🙈
- 提高开发效率: 简化服务之间的调用,减少代码量。 ⚡
- 提高系统稳定性: 通过负载均衡、故障转移等机制,提高系统的可用性。 🛡️
- 方便服务治理: 可以对服务进行监控、限流、熔断等管理。 ⚙️
4 Feign和OpenFeign都是什么?
Feign是RPC框架中的一种,是Netflix开发的声明式、模板化的HTTP客户端,底层依然是走的HTTP调用,但表现形式是接口调用,可以帮助我们更加便捷、优雅地调用HTTP API,就像调用本地方法一样方便。
它通过扩展集成了Netflix Ribbon,从而拥有负载均衡的功能,默认是基于配置来提供服务实例列表。
OpenFeign是指Spring Cloud OpenFeign,是Spring Cloud开发的,对Feign进行了增强,使其支持Spring MVC注解,还整合了Spring Cloud Netflix Ribbon,从注册中心获取服务实例(在Spring Cloud Alibaba框架中的注册中心默认是Nacos),从而使得Feign与Spring Cloud整合。
5 HTTP调用 vs Feign(RPC)调用
回顾一下RestTemplate方式的服务调用(gg-user是服务名):
@Autowired
private RestTemplate restTemplate;
@GetMapping("/getUserName")
public String getUserName(@RequestParam("id") Integer id) {
String url = String.format("http://%s/user?id=%s", "gg-user", id);
return restTemplate.exchange(url, HttpMethod.GET, null, String.class).getBody();
}
换成Feign调用,感受一下效果:
@Autowired
private UserService userService;
@GetMapping("/getUserName")
public String getUserName(@RequestParam("id") Integer id) {
return userService.getUserName(id);
}
What? Feign这个是远程调用?
对,这就是远程调用,丝毫看不出来,和调用本地方法一样的湿滑!
怎么实现的?如果你用过Mybatis,可以往Mybatis接口的实现类上思考,也许你能想到答案!
6 搭建工程
示例代码对应仓库:
- 网关服务:
oso-gateway- 认证中心:
oso-auth- 会员中心:
mall-ums
6.1 搭建父工程
创建oso-cloud项目,作为网关中心。最终项目代码如下图所示:

6.1.1 引入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.oso.cloud</groupId>
<artifactId>oso-cloud</artifactId>
<version>${revision}</version>
<packaging>pom</packaging>
<name>oso-cloud</name>
<description>oso-cloud</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<modules>
<module>oso-gateway</module>
<module>oso-auth</module>
<module>oso-common</module>
</modules>
<properties>
<revision>0.0.1</revision>
<java.version>17</java.version>
<maven.compiler.source>19</maven.compiler.source>
<maven.compiler.target>19</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring-boot.version>3.4.5</spring-boot.version>
<spring-cloud.version>2024.0.1</spring-cloud.version>
<spring-cloud-alibaba.version>2023.0.1.2</spring-cloud-alibaba.version>
<hutool.version>5.8.35</hutool.version>
<lombok.version>1.18.38</lombok.version>
<knife4j.version>4.3.0</knife4j.version>
<swagger.version>2.1.0</swagger.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- hutool 的依赖配置-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-bom</artifactId>
<version>${hutool.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<!-- API 接口文档 -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-dependencies</artifactId>
<version>${knife4j.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.oso.cloud</groupId>
<artifactId>common-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.oso.cloud</groupId>
<artifactId>common-web</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.oso.cloud</groupId>
<artifactId>ums-api</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>public</id>
<name>huawei nexus</name>
<url>https://mirrors.huaweicloud.com/repository/maven/</url>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>public</id>
<name>huawei nexus</name>
<url>https://mirrors.huaweicloud.com/repository/maven/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>
6.2 搭建公共模块
创建oso-common模块,作为公共依赖。最终项目代码如下图所示:

6.2.1 引入依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.oso.cloud</groupId>
<artifactId>oso-cloud</artifactId>
<version>${revision}</version>
</parent>
<artifactId>oso-common</artifactId>
<packaging>pom</packaging>
<name>oso-common</name>
<url>http://maven.apache.org</url>
<modules>
<module>common-core</module>
<module>common-web</module>
</modules>
<dependencies>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
6.2.2 创建common-core子模块

6.2.2.1 引入依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.oso.cloud</groupId>
<artifactId>oso-common</artifactId>
<version>${revision}</version>
</parent>
<artifactId>common-core</artifactId>
<name>common-core</name>
<url

2690

被折叠的 条评论
为什么被折叠?



