【微服务】Feign 远程调用

一、初识 Feign

1. 认识 Feign

以前利用 RestTemplate 发送远程调用代码如下

存在下面的问题:

  1. 代码可读性差,编程体验不统一

  2. 参数复杂URL难以维护

Feign 是一个声明式的http客户端,官方地址:https://github.com/OpenFeign/feign

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

​

2. 使用 Feign

  1. 在子工程 pom 引入依赖

    org.springframework.cloud spring-cloud-starter-openfeign
  2. 在 order-service 的启动类添加注解开启 Feign 功能

​

  1. 编写 Feign 客户端, 创建接口

​

  1. 使用 Fegin, 将接口注入进来直接调用方法

​

到此 Feign 就替代了 RestTempate, 下面是 RestTempate 实现远程调用,是不是上面的更优雅呢。

​

3. 小结

使用 Feign 步骤

  1. 子模块引入引入 openfeign 依赖
  2. 子模块启动类添加 @EnableFeignClients 注解
  3. 子模块添加接口编写方法
  4. 使用 Feign 替代 RestTemplate

二、自定义配置

1. Feign 自定义配置介绍

类型 作用 说明
feign.Loger.Level 修改日志界别 包括四种不同的级别:none、basic、headers、full
feign.codec.Decoder 响应结果的解析器 http 远程调用的结果做解析,如解析json字符串作为java对象
feign.codec.Encoder 请求参数编码 将请求参数编码,便于通过http请求发送
feign.Contract 支持的注解格式 默认是SpringMVC的注解
feign.Retryer 失败重试机制 请求失败的重试机制,默认是没有,不过会使用Ribbon的重试

日志级别

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

2. 案例

2.1 配置文件方式

  1. 局部生效,写具体的服务名

    feign:
    client:
    config:
    userservice: # 写具体服务名称,针对某个微服务的配置
    loggerLevel: FULL # 日志级别

  2. 全局生效, default

    feign:
    client:
    config:
    default: # 使用default为全局配置
    loggerLevel: FULL # 日志级别

2.2 java 代码方式

  1. 声明一个类,然后声明一个 Logger.Level 的对象:

    public class DefaultFeignConfiguration {
    @Bean
    public Logger.Level logLevel() {
    return Logger.Level.BASIC; // 日志级别
    }
    }

  2. 选择生效范围

  • 如果局部生效,放在 @FeignClient 注解中

    @FeignClient(value = "userservice", configuration = DefaultFeignConfiguration .class)

  • 如果是全局生效,放在模块的启动类中的 @EnableFeignClients 注解上

    @EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration .class)

三、Feign 使用优化

Feign 底层发起 HTTP 请求是依赖其它框架的,Feign 底层客户端实现如下

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

因此优化 Feign 的性能主要包

  • 使用连接池代替默认的URLConnection
  • 日志级别最好用basic或none
  1. 引入依赖

在 order-service 的pom文件中引入 apache 的 httpclient依赖:

复制代码
<!--引入HttpClient依赖-->
  <dependency>
        <groupId>io.github.openfeign</groupId>
        <artifactId>feign-httpclient</artifactId>
  </dependency>
  1. 配置连接池

    feign:
    httpclient:
    enabled: true # 支持HttpClient的开关
    max-connections: 200 # 最大连接数
    max-connections-per-route: 50 # 单个路径的最大连接数

四、最佳实践

Feign 的 客户端与 Controller 代码很相似,

Feign 客户端代码片段

服务提供者的 Controller 代码片段

下面介绍如何优化这些重复的代码

1. 方式一(继承)

继承: 给消费者的 FeignClient 和 服务提供者 Controller 定义统一的父接口作为标准。但这种方式不太推荐。

缺点:

  • 耦合度太高,如果父接口变了,继承它的子类都要变。
  • 参数列表中的注解映射并不会继承,因此Controller中必须再次声明方法、参数列表、注解

优点:

实现了代码共享

2. 方式二(抽取)

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

3. 基于抽取方式的案例

  1. 抽取:
  • 创建一个模块名为 feign-api 的模块
  • 在 feign-api 模块的 pom 引入依赖

    复制代码
    <!-- feign 依赖-->
          <dependency>
              <groupId>org.springframework.cloud</groupId>
              <artifactId>spring-cloud-starter-openfeign</artifactId>
          </dependency>
  • 把 order-service中编写的UserClient、User、DefaultFeignConfiguration复制到feign-api项目中。

  • 把 order-service 中 编写的UserClient、User、DefaultFeignConfiguration 删除,再 order-service 的 pom 文件中 引入 feign-api的依赖

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

  1. 测试

启动后发现报错了,找不到 UserClient 是什么情况呢?

原来是因为 userClient 在 cn.itcast.client 的包下,而 order-servcie 模块下调用 UserClient 是cn.itcast.order.service 包下,不在同个包下所以没有扫描出来。

有两个解决方案:

**方案1:**启动类中指定Feign应该扫描的包:

复制代码
@EnableFeignClients(basePackages = "cn.itcast.client")

**方案2:**在启动类中指定需要加载的Client接口字节码:

复制代码
@EnableFeignClients(clients = {UserClient.class})
相关推荐
Wang's Blog11 小时前
Java框架 SpringCloud 快速入门: 过滤器链执行顺序
java·spring cloud
写后端的胖头鱼12 小时前
【高频面试题】微服务项目排查错误流程(万字详解)
微服务·架构·问题定位·链路·线上排错
Wang's Blog14 小时前
Java框架 SpringCloud 快速入门: 服务拆分案例 Demo
java·开发语言·spring cloud
Wang's Blog17 小时前
Java框架 SpringCloud 快速入门: 服务拆分之服务远程调用
java·开发语言·spring cloud
Wang's Blog17 小时前
Java框架 SpringCloud 快速入门: 路由断言工厂
java·spring·spring cloud
Wang's Blog17 小时前
Java框架 SpringCloud 快速入门: Gateway 路由的过滤器配置
java·spring cloud·gateway
Wang's Blog20 小时前
Java框架 SpringCloud 快速入门: 从服务拆分到注册中心的落地路线
java·开发语言·spring cloud
Wang's Blog20 小时前
Java框架 SpringCloud 快速入门: 全局过滤器(GlobalFilter)自定义鉴权
java·开发语言·spring cloud
谢亮_vipxieliang1 天前
Spring Cloud 服务治理入门:注册发现、配置中心、网关限流、熔断降级与分布式一致性方案
分布式·spring·spring cloud
晚安code2 天前
RPC 到底是什么:微服务内部调用的首选,以及它藏起来的三个坑
微服务·rpc