• 声明式HTTP客户端-Feign 使用入门详解


    什么是 OpenFeign

    OpenFeign (以下统一简称为 Feign) 是 Netflix 开源的声明式 HTTP 客户端,集成了 Ribbon 的负载均衡、轮询算法和 RestTemplate 的 HTTP 调用等特性,并对其进行封装,使用者只需要在此基础上,定义一个接口,并在接口上标注一个 FeignClient ,便可以实现 HTTP 远程调用,上面的声明式 HTTP 如何理解,可以理解为

    ​ 只需要声明一个接口,Feign 就会通过你定义的接口,自动给你构造请求的目标地址并请求。

    下面介绍下如何在项目中集成 Feign 组件,只需要遵循 SpringBoot 开发三板斧(1、加依赖,2、加注解,3、加配置)即可

    环境准备

    1. 加依赖 openfeign

      <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-openfeign</artifactId>
      </dependency>
      
      • 1
      • 2
      • 3
      • 4
    2. 加注解 @EnableFeignClients

      @SpringBootApplication
      @EnableFeignClients
      public class Application {
          public static void main(String[] args) {
              SpringApplication.run(Application.class, args);
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
    3. 加配置(由于 feign 不需要额外在 application.yml 或者 application.properties)中配置,只需要配置好调用微服务的名称和端口即可,下面举个例子,user-center 就是我们调用的微服务

      server:
        port: 8081
      spring:
        cloud:
          nacos:
            discovery:
              server-addr: localhost:8848
        # 微服务名称
        application:
          name: user
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10

    新建 OpenFeign 接口

    @FeignClient(name = "user")
    public interface UserFeignClient {
        @GetMapping("/users/{id}")
        UserDto findById(@PathVariable Integer id);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    新建 Controller 层

    @Service
    public class ArticleController {
    
        @Resource
        private UserFeignClient userFeignClient;
    
        public ArticleDto findByUserId(Integer userId) {
            ... ...
            ArticleDto articleDto = this.userFeignClient.findById(userId);
            ... ...
            return articleDto;
    
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    以上,就是 openFeign 的基本使用入门了

    Feign的日志配置

    由于 Feign 在没有配置的情况下是不会打印任何日志,如果想要看到 Feign 的日志,需要额外的配置;但是在此之前,我们先了解下 Feign 的自定义日志级别。

    Feign 的自定义日志级别

    级别打印内容
    NONE(默认值)不记录任何日志
    BASIC仅记录请求方法、URL、响应状态码以及执行时间
    HEADERS记录 BASIC 级别的基础上,记录请求和响应的 header
    FULL记录请求和响应的 header、body 和元数据

    Feign 的自定义日志级别可以通过 Java 代码方式或配置属性方式来实现,下面我们先介绍下代码的实现方式

    代码配置方式

    1. 编写一个 Configuration 的类

      public class UserFeignConfiguration {
          @Bean
          public Logger.Level level() {
              //	生产上不建议使用FULL,这样会产生大量的日志,影响性能的同时还不好定位问题。
              //	建议使用 BASIC
              return Logger.Level.FULL;
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
    2. 然后在对应的 Feign 接口设置 Configuration 类

      @FeignClient(name = "user", configuration = UserFeignConfiguration.class)
      public interface UserFeignClient {
          @GetMapping("/users/{id}")
          UserDto findById(@PathVariable Integer id);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
    3. 最后还要将 Feign接口类的全路径设置在 yml 文件里面

      logging:
        level:
      	# Feign接口类的全路径 
      	# Feign的日志级别是建立在Feign的接口 debug 级别之上的
          com.example.article.feignclient.UserFeignClient: debug
      
      • 1
      • 2
      • 3
      • 4
      • 5

      当调用接口时,输出日志结果如下

      [UserFeignClient#findById] <--- HTTP/1.1 200 (794ms)
      [UserFeignClient#findById] content-type: application/json;charset=UTF-8
      [UserFeignClient#findById] date: Mon, 29 Aug 2022 10:56:27 GMT
      [UserFeignClient#findById] transfer-encoding: chunked
      [UserFeignClient#findById] 
      [UserFeignClient#findById] {"id":1,"username":"张三","createTime":"2022-08-25T17:17:04.000+0000","updateTime":"2022-08-25T17:17:04.000+0000"}
      [UserFeignClient#findById] <--- END HTTP (180-byte body)
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

      这样,通过代码来设置 Feign 的日志自定义级别方式就配置好了。但是这样,并不是完美的解决方案,就相当于每次新建一个 Feign 接口,就要编写一个对应的 xxxFeignConfiguration 类,然后在 Feign 接口上指定,这样下来太繁琐了,下面看下全局的代码配置方式:

      不需要在 每个 Feign 接口上面都要配置下 configuration = UserFeignConfiguration.class,我们只需要在 Application 启动类上面,指定 @EnableFeignClients(defaultConfiguration = GlobalFeignConfiguration.class),注:这里将 UserFeignConfiguration 已经更名为 GlobalFeignConfiguration

      @SpringBootApplication
      @EnableFeignClients(defaultConfiguration = GlobalFeignConfiguration.class)
      public class Application {
          public static void main(String[] args) {
              SpringApplication.run(Application.class, args);
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

    属性配置方式

    在 application.yml 加入只需要配置以下的属性既可以实现 Feign 的自定义级别

    feign:
      client:
        config:
          # 微服务名称
          user:
            loggerLevel: full
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    同理,yml 文件也支持 全局的属性配置方式

    feign:
      client:
        config:
          # 全局配置(default 默认就是适用于全部微服务)
          default:
            loggerLevel: full
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    Feign的多参数请求构造

    GET 请求

    请求多参数的URL,如请求地址为 http://www.xxx.me/admin/user/get?username=张三&school=阳光小学&birthDay=2012-08-01,SpringCloud 为 Feign 整合了 SpringMVC 的注解支持

    1. @SpringQueryMap 注解

      @FeignClient("user")
      public interface UserFeignClient {
        @RequestMapping(value = "/get", method = RequestMethod.GET)
        public User get(@SpringQueryMap User user);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
    2. @RequestParam注解(表单传参)

      @FeignClient("user")
      public interface UserFeignClient {
        @RequestMapping(value = "/get", method = RequestMethod.GET)
        public User get(@RequestParam("username") String username, @RequestParam("school") String school, @RequestParam("birthDayDay") String birthDay);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
    3. @PathVariable注解(URL携带参数)

      @FeignClient("user")
      public interface UserFeignClient {
        @RequestMapping(value = "/get", method = RequestMethod.GET)
        public User get(@PathVariable("username") String username, @PathVariable("school") String school, @PathVariable("birthDayDay") String birthDay);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5

    POST 请求

    Feign 默认的传参方式就是 JSON 传参(@RequestBody),因此定义接口的时候可以不用@RequestBody注解标注,但为了开发规范,建议加上

    1. @RequestBody 注解

      @FeignClient("user")
      public interface UserFeignClient {
        @RequestMapping(value = "/post", method = RequestMethod.POST)
        public User post(@RequestBody User user);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5

    超时设置

    我们在通过 Feign 去调用接口,难免会遇到超时的问题,我们可以在 yml 文件设置超时属性,防止系统抛出超时异常

    feign:
        client:
            config:
    		   # 全局配置(default 默认就是适用于全部微服务)
                default:
                    connectTimeout: 100000
                    readTimeout: 100000
                # 单独配置
                user:
                    connectTimeout: 300000
                    readTimeout: 300000
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    Feign 性能优化

    默认情况下,Feign 使用的是 UrlConnetcion 去请求,这种原生的请求方式一旦遇到高并发的情况下,响应会变得很慢,所以我们可以考虑加入连接池技术来优化性能,下面介绍下如何集成 Apache 下的 HttpClient 的连接池

    1. 加入 httpclient 依赖

      <dependency>
          <groupId>io.github.openfeign</groupId>
          <artifactId>feign-httpclient</artifactId>
      </dependency>
      
      • 1
      • 2
      • 3
      • 4
    2. 设置 yml 文件属性

      feign:
      	# 这样就设置好了 feign 请求方式是 httpclient,而不是 UrlConnetcion 
          httpclient:
              enable: true
      	    # feign的最大连接数
              max-connection: 200
       	    # feign 单个路径的最大连接数
              max-connections-per-route: 50
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
  • 相关阅读:
    英语学术论文简短语句摘抄
    一文带您了解什么是渲染农场
    小程序支付升级:实现微信支付V3接口接入
    使用Object.key和delete来将对象中值为空的属性删除。
    day02 springmvc
    Vue.js+Node.js全栈开发教程:Vue.js指令修饰符详解
    java 面向对象
    聊一聊华为云弹性公网IP的那些事儿
    在k8s中创建ConfigMap的四种方式与初识helm包管理工具
    oslo_messaging学习系列之二《OpenStack中使用消息队列》
  • 原文地址:https://blog.csdn.net/hyx1249273846/article/details/126615539