1. RestTemplate存在问题
之前的代码:

虽说RestTemplate 对HTTP封装后, 已经⽐直接使⽤HTTPClient简单⽅便很多, 但是还存在⼀些问题.
1. 需要拼接URL, 灵活性⾼, 但是封装臃肿, URL复杂时, 容易出错.
2. 代码可读性差, ⻛格不统⼀.
微服务之间的通信⽅式, 通常有两种: RPC 和 HTTP.
在SpringCloud中, 默认是使⽤HTTP来进⾏微服务的通信, 最常⽤的实现形式有两种:
- RestTemplate
- OpenFeign
RPC(Remote Procedure Call)远程过程调⽤,是⼀种通过⽹络从远程计算机上请求服务,⽽不需要了解底层⽹络通信细节。
RPC可以使⽤多种⽹络协议进⾏通信, 如HTTP、TCP、UDP等, 并且在 TCP/IP⽹络四层模型中跨越了传输层和应⽤层。简⾔之RPC就是像调⽤本地⽅法⼀样调⽤远程⽅法。 常⻅的RPC框架有Dubbo,Thrift,gRPC
2. OpenFeign介绍
OpenFeign 是⼀个声明式的 Web Service 客⼾端. 它让微服务之间的调⽤变得更简单, 类似controller 调⽤service, 只需要创建⼀个接⼝,然后添加注解即可使⽤OpenFeign.
Spring Cloud Feign
Spring Cloud Feign 是 Spring 对 Feign 的封装, 将 Feign 项⽬集成到 Spring Cloud ⽣态系统中.
受 Feign 更名影响,Spring Cloud Feign 也有两个 starter:
- spring-cloud-starter-feign
- spring-cloud-starter-openfeign
由于Feign的停更维护, 对应的, 我们使⽤的依赖是 spring-cloud-starter-openfeign
3. 使用
3.1 依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
3.2 注解
在order-service的启动类添加注解 @EnableFeignClients , 开启OpenFeign的功能.

3.3 编写OpenFeign的客⼾端

@FeignClient(value = "product-service",path = "/product")
public interface ProductApi {
//方法声明
@RequestMapping("/{productId}")
ProductInfo getProductInfo(@PathVariable("productId") Integer productId);
}
@FeignClient 注解作⽤在接⼝上, 参数说明:
name/value:指定FeignClient的名称, 也就是微服务的名称, ⽤于服务发现, Feign底层会使⽤ Spring Cloud LoadBalance进⾏负载均衡. 也可以使⽤ url 属性指定⼀个具体的url.
path: 定义当前FeignClient的统⼀前缀.
3.4 远程调⽤
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private ProductApi productApi;
public OrderInfo selectOrderById(Integer orderId){
OrderInfo orderInfo = orderMapper.selectOrderById(orderId);
ProductInfo productInfo = productApi.getProductById(orderInfo.getProductId());
orderInfo.setProductInfo(productInfo);
return orderInfo;
}
}
3.5 测试
Feign 简化了与HTTP服务交互的过程, 把REST客⼾端的定义转换为Java接⼝, 并通过注解的⽅式来声明请求参数,请求⽅式等信息, 使远程调⽤更加⽅便和间接.
4. OpenFeign参数传递
通过观察, 我们也可以发现, Feign的客⼾端和服务提供者的接⼝声明⾮常相似
接下来演⽰下Feign参数传递的其他⽅式
4.1 传递单个参数
使⽤多个@RequestParam 进⾏参数绑定即可
服务提供⽅ product-service:
方法实现

Feign客户端:
方法声明

order-service:

4.2 传递多个参数
使⽤多个@RequestParam 进⾏参数绑定即可



4.3 传递对象

4.4 传递JSON



5. 最佳实践
通过观察, 我们也能看出来, Feign的客⼾端与服务提供者的controller代码⾮常相似
有没有⼀种⽅法可以简化这种写法呢?
5.1 Feign继承方式
Feign ⽀持继承的⽅式, 我们可以把⼀些常⻅的操作封装到接⼝⾥.
我们可以定义好⼀个接⼝, 服务提供⽅实现这个接⼝, 服务消费⽅编写Feign 接⼝的时候, 直接继承这个接⼝
5.1.1 创建一个Model
product-api
5.1.2 依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency><dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
5.1.3 接口编写
复制 ProductApi, ProductInfo 到product-api模块中
public interface ProductInterface {
//方法声明
@RequestMapping("/{productId}")
ProductInfo getProductById(@PathVariable("productId") Integer productId);
@RequestMapping("/p1")
String p1(@RequestParam("id") Integer id);
@RequestMapping("/p2")
String p2(@RequestParam("id") Integer id,@RequestParam("name") String name);
@RequestMapping("/p3")
String p3(@SpringQueryMap ProductInfo productInfo);
@RequestMapping("/p4")
String p4(@RequestBody ProductInfo productInfo);
}
5.1.4 Jar包
通过Maven打包

5.1.5 服务提供方
服务提供⽅实现接⼝ ProductInterface

5.1.6 服务消费方
服务消费⽅继承ProductInterface
5.1.7 测试
5.2 Feign抽取方式
官⽅推荐Feign的使⽤⽅式为继承的⽅式, 但是企业开发中, 更多是把Feign接⼝抽取为⼀个独⽴的模块 (做法和继承相似, 但理念不同).
操作⽅法: 将Feign的Client抽取为⼀个独⽴的模块, 并把涉及到的实体类等都放在这个模块中, 打成⼀个Jar.
服务消费⽅只需要依赖该Jar包即可. 这种⽅式在企业中⽐较常⻅, Jar包通常由服务提供⽅来实现
5.2.1 创建⼀个module
product-api
5.2.2 依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
5.2.3 编写API
复制 ProductApi, ProductInfo 到product-api模块中
同上
5.2.4 Jar包
同上
5.2.5 服务消费⽅使⽤product-api
①删除ProductApi, ProductInfo
②引入依赖
<dependency>
<groupId>org.example</groupId>
<artifactId>product-api</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
修改项⽬中ProductApi, ProductInfo的路径为product-api中的路径
③指定扫描类: ProductApi
在启动类指定需要加载的Feign客⼾端

5.2.6 测试
略
1163

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



