远程调用 - OpenFeign
目录
RestTemplate 问题
OpenFeign
快速使用
OpenFeign 参数传递
传递单个参数
传递多个参数
传递对象
传递 JSON 字符串
最佳实践
Feign 继承方式
创建一个 Module
打 Jar 包
服务提供方
服务消费方
Feign 抽取方式
创建一个 module
引入依赖
API
打 Jar 包
服务消费方使用 product-api
部署服务
学习 OpenFeign 可以使用前面的 nacos 的代码~
RestTemplate 问题
远程调用的代码:

RestTemplate 对 HTTP 封装之后,较为简单方便,但还是存在一些问题。
1. URL 需要拼接,灵活度高,但封装时易出错。
2. 代码可读性差,风格不统一
微服务之间的通信方式有两种:RPC 和 HTTP
SpringCloud 中,默认使用 HTTP来进行微服务的通信,常用的实现方式有两种:
RestTemplate 和 OpenFeign
RPC 远程调用,是一种通过网络,从远程计算机上请求服务,而不需要了解底层网络通信细节。 RPC 可以使用多种网络协议进行通信,HTTP,TCP,UDP... 并且在 TCP/IP 网络四层模型中,跨越了传输层和应用层。
总而言之,RPC 就像调用本地方法一样调用远程方法~~
常见的 RPC 框架:
1. Dubbo:Apache Dubbo
2. Thrift:Apache Thrift - Home
3. gRPC:gRPC
OpenFeign
OpenFeign 是一个声明式的 Web Service 客户端,它让微服务之间的调用变得更简单。类似 controller 调用 service,只需要创建一个接口,然后添加注解即可使用。
OpenFeign 发展历史
快速使用
1. 引入依赖
在 order-service 中引入对应的依赖:

由于 Feign 底层也会使用 Spring Cloud LoadBalance 进行负载均衡
还需要导入负载均衡的依赖

2. 添加注解
在 order-service 的启动类添加注解 @EnableFeginClients,开启 OpenFeign 的功能

3. 编写 OpenFeign 的客户端
在 order-service 中创建 api 包,包下创建 ProductApi 接口类

@FeigbClient 注解作用在接口上,说明如下:
name/value:指定 FeignClient 的名称,也就是微服务的名称,用于服务发现,Feign 底层也会使用 Spring Cloud LoadBalance 进行负载均衡。
path:定义当前 FeignClient 的统一前缀。
4. 远程调用

将 ProductApi 接口注入,然后直接调用方法
5. 测试
启动服务,nacos,访问接口

使用 Feign 也可以实现远程调用。
Feign 简化了与 HTTP 服务交互的过程,把 REST 客户端的定义转换为 Java 接口,并通过注解的方式来声明请求参数,请求信息等,使远程调用更加方便和简洁。
OpenFeign 参数传递
OpenFeign 的客户端(即我们上文实现的 ProductApi)和服务提供者的接口声明非常相似。

上面例子中,只演示了 Feign 从 URL 中获取参数,下面是 Feign 参数传递的方式
传递单个参数
1. 服务端需要提供相应的接口


2. Feign 客户端

注意:@RequestParam 做参数绑定,不可以省略。
3. 服务消费方 order-service


传递多个参数
使用多个 @RequestParam 进行参数绑定即可~
1. 服务端提供对应接口:

2. Feign 客户端

3. 服务消费方 order-service

测试

传递对象
1. 服务端提供对应接口:

2. Feign 客户端
注意参数前面要有 @SpringQueryMap 注解

3. 服务消费方 order-service


传递 JSON 字符串
1. 服务端提供对应接口:

2. Feign 客户端

3. 服务消费方 order-service


最佳实践
即,在具体的项目过程中,总结出来的最好的使用方式。
通过观察,Feign 的客户端和服务提供者的 controller 代码非常相似

Feign 继承方式
Feign 支持继承的方式,我们可以将一些常见的操作,封装到一个接口中
即,定义好一个接口,服务提供方实现这个接口,服务消费方编写 Feign 接口的时候,直接继承这个接口即可~~
创建一个 Module
接口放在一个公共的 Jar 包中,供服务提供方和服务消费方使用
引入依赖:

目录结构如下:

将 ProductApi 和 ProductInfo 复制到 product-api 模块中

因为 order-service 和 product-service 中都需要 ProductInfo,所以我们直接将其提取出来在 product-api,然后就可以将之前两个模块重点 ProductInfo 全部注释掉了~~


打 Jar 包
通过 Maven 打包

观察 Maven 本地仓库,是否成功打包


服务提供方
服务提供方实现接口 ProductInterface
在 ProductController 方法中实现接口

但我们这个接口的定义是在其他模块中,由于刚刚已经打成了 jar 包放在了我们的本地 maven 仓库中,所以当我们使用快捷键修复的时候,会自动提示我们添加依赖~~
可以在 pom 文件中看到我们刚刚打的 jar 包已经被添加进来了~~

此时进行接口的实现:
注意!由于我们在前面将 ProductInfo 对象抽取到了新的 jar 包 product-api 中,所以之前导入的 ProductInfo 类全会报错,之前的 ProductInfo 都是来自各自模块中的 ProductInfo,现在都被我们注释掉了,需要重新导一下包~~(此处没有报错是因为我已经都导完了~~)

服务消费方
同样的,在 order-service 中,ProductInfo 相关的类的也需要重新导包~
服务消费方继承 ProductInterface

order-service 中的 service 层代码不需要变化

测试:


总的来说:是将我们前面快速上手中,在 order 中的 TestFeignController 的代码,抽象出了一个模块的接口,然后将那个模块打成 jar 包,分别引入 product 和 order 中,在 product 中进行实现,在 order 中进行继承~~
Feign 抽取方式
官方推荐方式为继承的方式,但企业开发中更多将 Feign 接口抽象为一个独立的模块(做法和继承相似,理念不同)
方法:
将 Feign 的 Client 抽取为一个独立的模块,并把涉及到的实体类都放在这个模块中,打成一个 Jar 包。服务消费方只需要依赖 Jar 包即可。Jar 包通常由服务提供方来实现。
创建一个 module

引入依赖

API
将 ProductApi 和 ProductInfo 到 product-api 模块中

打 Jar 包

服务消费方使用 product-api
1. 将 order-service 中的 ProductApi 和 ProductInfo 全部删掉
2. 将打好的 jar 包引入进来

使用之前路径的 ProductApi 和 ProductInfo 全部会报错,需要将路径更换为 product-api 中的路径
3. 指定扫描类:ProductApi
在启动类的 @EnableFeignClients 中添加扫描类

启动服务,测试远程调用

部署服务
1. 将数据库 Nacos 等配置进行修改
2. 对两个服务进行打包
Maven 打包默认是从远程仓库下载的,product-api 这个包在本地,解决方案:
1. 将我们的包上传到 Maven 中央仓库(麻烦,不好弄)
2. 搭建 Maven 私服,将 Jar 包上传到私服(企业使用)
3. 从本地读取 Jar 包(学习阶段使用~~)
从本地读取 Jar 包:
修改 pom 文件


systemPath 标签中的路径,对应我们本地的 Maven 仓库的地址
3. 上传 jar 包到 Linux 服务器
4. 启动 Nacos(启动前可以将 data 数据删除掉)
5. 启动服务


6. 测试符合预期~

