Spring cloud 之Feign远程调用

2022-11-07 14:30:48 浏览数 (1)

上一篇博客: SpringCloud之Nacos配置管理【统一配置管理,配置热更新,配置共享】_一切总会归于平淡的博客-CSDN博客

目录

1、Feign替代RestTemplate

1.1 引入依赖

1.2 添加注解

1.3 编写Feign的客户端

1.4 测试

2、定义配置

2.1 配置文件方式

2.2.Java代码方式

3、Feign使用优化

3.1 引入依赖

3.2 配置连接池

4、最佳实践

4.1 继承方式

4.2 抽取方式

4.3 实现基于抽取的实践

4.3.1 抽取

4.3.2 在order-service中使用feign-api

4.3.3 解决扫描包问题


先来看我们以前利用RestTemplate发起远程调用的代码:

存在下面的问题:

  • 代码可读性差,编程体验不统一
  • 参数复杂URL难以维护

Feign是一个声明式的http客户端,官方地址:GitHub - OpenFeign/feign: Feign makes writing java http clients easier

其作用就是帮助我们优雅的实现http请求的发送,解决上面提到的问题。

1、Feign替代RestTemplate

1.1 引入依赖

我们在order-service服务的pom文件中引入feign的依赖:

代码语言:javascript复制
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

1.2 添加注解

在order-service的启动类添加注解开启Feign的功能:

1.3 编写Feign的客户端

在order-service中新建一个接口,内容如下:

代码语言:javascript复制
package com.jie.order.config;


import com.jie.order.entity.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient("userservice")
public interface UserClient {
    @GetMapping("/user/{id}")
    User findById(@PathVariable("id") Long id);
}

这个客户端主要是基于SpringMVC的注解来声明远程调用的信息,比如:

  • 服务名称:userservice
  • 请求方式:GET
  • 请求路径:/user/{id}
  • 请求参数:Long id
  • 返回值类型:User

这样,Feign就可以帮助我们发送http请求,无需自己使用RestTemplate来发送了。

1.4 测试

修改order-service中的OrderService类中的queryOrderById方法,使用Feign客户端代替RestTemplate:

2、定义配置

Feign可以支持很多的自定义配置,如下表所示:

类型

作用

说明

feign.Logger.Level

修改日志级别

包含四种不同的级别:NONE、BASIC、HEADERS、FULL

feign.codec.Decoder

响应结果的解析器

http远程调用的结果做解析,例如解析json字符串为java对象

feign.codec.Encoder

请求参数编码

将请求参数编码,便于通过http请求发送

feign. Contract

支持的注解格式

默认是SpringMVC的注解

feign. Retryer

失败重试机制

请求失败的重试机制,默认是没有,不过会使用Ribbon的重试

一般情况下,默认值就能满足我们使用,如果要自定义时,只需要创建自定义的@Bean覆盖默认Bean即可。

下面以日志为例来演示如何自定义配置。

2.1 配置文件方式

基于配置文件修改feign的日志级别可以针对单个服务,比如我在order-service的配置文件力进行配置:

代码语言:javascript复制
feign:  
  client:
    config: 
      userservice: # 针对某个微服务的配置
        loggerLevel: FULL #  日志级别 

也可以针对所有服务:

代码语言:javascript复制
feign:  
  client:
    config: 
      default: # 这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置
        loggerLevel: FULL #  日志级别 

我们重启服务,发个请求看看效果。

而日志的级别分为四种:

  • NONE:不记录任何日志信息,这是默认值。
  • BASIC:仅记录请求的方法,URL以及响应状态码和执行时间
  • HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息
  • FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据。

2.2.Java代码方式

也可以基于Java代码来修改日志级别,先声明一个类,然后声明一个Logger.Level的对象:

如果要全局生效,将其放到启动类的@EnableFeignClients这个注解中:

如果是局部生效,则把它放到对应的@FeignClient这个注解中:

3、Feign使用优化

Feign底层发起http请求,依赖于其它的框架。其底层客户端实现包括:

  • URLConnection:默认实现,不支持连接池
  • Apache HttpClient :支持连接池
  • OKHttp:支持连接池

因此提高Feign的性能主要手段就是使用连接池代替默认的URLConnection;日志级别,最好用basic或none

这里我们用Apache的HttpClient来演示。

3.1 引入依赖

在order-service的pom文件中引入Apache的HttpClient依赖:

代码语言:javascript复制
<!--httpClient的依赖 -->
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-httpclient</artifactId>
        </dependency>

3.2 配置连接池

在order-service的application.yml中添加配置:

代码语言:javascript复制
feign:
  client:
    config:
      userservice: # 针对某个微服务的配置
        loggerLevel: FULL #  日志级别
  httpclient:
    enabled: true # 开启feign对HttpClient的支持
    max-connections: 200 # 最大的连接数
    max-connections-per-route: 50 # 每个路径的最大连接数

4、最佳实践

观察可以发现,Feign的客户端与服务提供者的controller代码非常相似:

有没有一种办法简化这种重复的代码编写呢?

4.1 继承方式

一样的代码可以通过继承来共享:

1、定义一个API接口,利用定义方法,并基于SpringMVC注解做声明。

2、Feign客户端和Controller都集成改接口

优点:

  • 简单
  • 实现了代码共享

缺点:

  • 服务提供方、服务消费方紧耦合
  • 参数列表中的注解映射并不会继承,因此Controller中必须再次声明方法、参数列表、注解

4.2 抽取方式

将Feign的Client抽取为独立模块,并且把接口有关的entity、默认的Feign配置都放到这个模块中,提供给所有消费者使用。

例如,将UserClient、User、Feign的默认配置都抽取到一个feign-api包中,所有微服务引用该依赖包,即可直接使用。

优点:解决了耦合度问题。

缺点:方法全部封装起来了,调用时可能只需要调用其中个别方法,但是这种方法会将所有方法引用进来,就显得有点多余了。

4.3 实现基于抽取的实践

4.3.1 抽取

首先创建一个module,命名为feign-api:

在feign-api中然后引入feign的starter依赖

代码语言:javascript复制
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

然后,order-service中编写的UserClient、User、DefaultFeignConfiguration都复制到feign-api项目中

4.3.2 在order-service中使用feign-api

首先,删除order-service中的UserClient、User、DefaultFeignConfiguration等类或接口。

在order-service的pom文件中引入feign-api的依赖:

代码语言:javascript复制
<dependency>
            <groupId>com.jie.demo</groupId>
            <artifactId>feign-api</artifactId>
            <version>1.0</version>
        </dependency>

修改order-service中的所有与上述三个组件有关的导包部分,改成导入feign-api中的包

4.3.3 解决扫描包问题

因为UserClient现在在com.jie.feign.client包下,而order-service的@EnableFeignClients注解是在com.jie.order包下,不在同一个包,无法扫描到UserClient。

方式一:

指定Feign应该扫描的包:

代码语言:javascript复制
@EnableFeignClients(basePackages = "com.jie.feign.clients")

方式二:

指定需要加载的Client接口:

代码语言:javascript复制
@EnableFeignClients(clients = {UserClient.class})

若有收获就点一个赞吧

0 人点赞