跳至主要內容

OpenFeign

sixkey大约 6 分钟后端SpringCloud微服务OpenFeign

OpenFeign

Cloud之OpenFeign

是什么?

OpenFeign是一个声明式的Web服务客户端

能干嘛?

  • 可插拔的注解支持,包括Feign注解和JAX-RS注解
  • 支持可插拔的HTTP编码器和解码器
  • 支持SentineI和它的Fallback
  • 支持SrinCloudLoadBalancer的负载均衡
  • 支持HTTP请求和响应的压缩

怎么玩?

1、接口 + 注解

架构说明图

screenshot-1712827051217
screenshot-1712827051217

2、流程步骤

①、建Model

cloud-consumer-openfeign-order

②、改pom

<dependencies>
        <!--openfeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!--SpringCloud consul discovery-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
        <!-- 引入自己定义的api通用包 -->
        <dependency>
            <groupId>com.atguigu.cloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!--web + actuator-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--hutool-all-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
        </dependency>
        <!--fastjson2-->
        <dependency>
            <groupId>com.alibaba.fastjson2</groupId>
            <artifactId>fastjson2</artifactId>
        </dependency>
        <!-- swagger3 调用方式 http://你的主机IP地址:5555/swagger-ui/index.html -->
        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

写yml

server:
  port: 7999

spring:
  application:
    name: cloud-consumer-openfeign-order
  ####Spring Cloud Consul for Service Discovery
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        prefer-ip-address: true #优先使用服务ip进行注册
        service-name: ${spring.application.name}

主启动类开启注解@EnableFeignClients

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class OpenFeignConsumerApp
{
    public static void main( String[] args )
    {
        SpringApplication.run(OpenFeignConsumerApp.class,args);
    }
}

apis包下包含所有向外暴露的接口api

screenshot-1712828110614
/**
 * 支付模块相关接口
 * 注意:一定要添加注解@FeignClient,否则无法远程调用服务
 * name的值为提供服务类的应用名称
 */
@FeignClient(name = "cloud-payment-service")
public interface PaymentFeignService {
    @GetMapping("/pay/add")
    ResultData addOrder(PayDto payDTO);

    @GetMapping("/pay/query/{orderNo}")
    ResultData queryOrder(@PathVariable("orderNo") String orderNo);
}

controller调用服务

@Slf4j
@RestController
@RequestMapping("/feign")
@RequiredArgsConstructor
public class PaymentFeignController {

    private final PaymentFeignService paymentFeignService;

    /**
     * 一般情况下,通过浏览器的地址栏输入url,发送的只能是get请求
     * 我们底层调用的是post方法,模拟消费者发送get请求,客户端消费者
     * 参数可以不添加@RequestBody
     * @param payDTO
     * @return
     */
    @GetMapping("/pay/add")
    public ResultData addOrder(PayDto payDTO){
        paymentFeignService.addOrder(payDTO);
        return ResultData.success();
    }

    /**
     * @param orderNo
     * @return
     */
    @GetMapping("/pay/query/{orderNo}")
    public ResultData queryOrder(@PathVariable("orderNo") String orderNo){
        ResultData result = paymentFeignService.queryOrder(orderNo);
        return ResultData.success(result.getData());
    }
}

3、小总结

重点说明:OpenFeign自带负载均衡功能,默认是轮询

screenshot-1712829454383
screenshot-1712829454383

高级特性

1、超时控制

默认OpenFeign客户端等待60秒钟,但是服务端处理超过规定时间会导致Feign客户端返回报错。

为了避免这样的情况,有时候我们需要设置Feign客户端的超时控制,默认60秒太长或者业务时间太短都不好

yml文件中开启配置:

connectTimeout 连接超时时间

readTimeout 请求处理超时时间

screenshot-1712841720091
screenshot-1712841720091

如何控制呢?

修改cloud-consumer-openfeign-order 的yml配置文件开启OpenFeign客户端超时控制

screenshot-1712841837845

开始配置

  • 全局配置

    • 修改yml配置文件,添加以下内容即可

      spring:
        cloud:
          openfeign:
            client:
              config:
                default:
                  #连接超时时间
                   connectTimeout: 3000
                  #读取超时时间
                   readTimeout: 3000
      
  • 指定特定服务配置

    • 可以指定为某个服务提供者的超时时间控制,如支付模块

      spring:
        application:
          name: cloud-consumer-openfeign-order
        ####Spring Cloud Consul for Service Discovery
        cloud:
          consul:
            host: localhost
            port: 8500
            discovery:
              prefer-ip-address: true #优先使用服务ip进行注册
                      service-name: ${spring.application.name}
          openfeign:
            client:
              config:
               #default:
                  #connectTimeout: 4000 #连接超时时间
                  #readTimeout: 4000 #读取超时时间
               cloud-payment-service:
                  connectTimeout: 8000 #连接超时时间
                  readTimeout: 8000 #读取超时时间
      

特别说明:当全局和指定配置都配置时,优先遵循指定配置超时时间控制

2、重试机制

有默认值,但是被官方关闭了

screenshot-1712843153808

开启重试机制

新增配置类:FeignConfig并修改Retryer配置

/**
 * ClassName: FeignConfig
 * Package: org.cloud.config
 * Description:
 *
 * @Author: @weixueshi
 * @Create: 2024/4/11 - 21:48
 * @Version: v1.0
 */

/**
 * 重试机制配置
 */
@Configuration
public class FeignConfig
{
    @Bean
    public Retryer myRetryer()
    {
        //return Retryer.NEVER_RETRY; //Feign默认配置是不走重试策略的

        //最大请求次数为3(1+2),初始间隔时间为100ms,重试间最大间隔时间为1s
        return new Retryer.Default(100,1,3);
    }
}

3、默认HttpClient替换

是什么?

OpenFeign中http client如果不做特殊配置,OpenFeign默认使用JDK自带的HttpURLConnection发送HTTP请求,

由于默认HttpURLConnection没有连接池、性能和效率比较低,如果采用默认,性能上不是最牛B的,所以加到最大。

替换之前,默认使用的

screenshot-1712843536484
screenshot-1712843536484

替换为Apache HttpClient 5

修改cloud-consumer-openfeign-order

导入依赖

<dependency>
    <groupId>org.apache.httpcomponents.client5</groupId>
    <artifactId>httpclient5</artifactId>
    <version>5.3</version>
</dependency>
<!-- feign-hc5-->
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-hc5</artifactId>
    <version>13.1</version>
</dependency>

写yaml

spring:
  application:
    name: cloud-consumer-openfeign-order
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        prefer-ip-address: true #优先使用服务ip进行注册
        service-name: ${spring.application.name}
    openfeign:
      client:
        config:
          default:
            #连接超时时间
            connectTimeout: 4000
            #读取超时时间
            readTimeout: 4000
      #  Apache HttpClient5 配置开启
      httpclient:
        hc5:
          enabled: true

替换之后使用的HttpClient

screenshot-1712845643443
screenshot-1712845643443

4、请求响应 / 压缩

官网说明

screenshot-1712845895260
screenshot-1712845895260

是什么?

对请求和响应进行GZIP压缩

Spring Cloud OpenFeign支持对请求和响应进行GZIP压缩,以减少通信过程中的性能损耗。

通过下面的两个参数设置,就能开启请求与相应的压缩功能:

spring.cloud.openfeign.compression.request.enabled=true

spring.cloud.openfeign.compression.response.enabled=true

细粒度化设置

对请求压缩做一些更细致的设置,比如下面的配置内容指定压缩的请求数据类型并设置了请求压缩的大小下限,

只有超过这个大小的请求才会进行压缩:

spring.cloud.openfeign.compression.request.enabled=true

spring.cloud.openfeign.compression.request.mime-types=text/xml,application/xml,application/json #触发压缩数据类型

spring.cloud.openfeign.compression.request.min-request-size=2048 #最小触发压缩的大小

修改cloud-consumer-openfeign-order

写yml

spring:
  application:
    name: cloud-consumer-openfeign-order
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        prefer-ip-address: true #优先使用服务ip进行注册
        service-name: ${spring.application.name}
    openfeign:
      client:
        config:
          default:
            #连接超时时间
            connectTimeout: 4000
            #读取超时时间
            readTimeout: 4000
      httpclient:
        hc5:
          enabled: true
      compression:
        request:
          enabled: true
          min-request-size: 2048 #最小触发压缩的大小
          mime-types: text/xml,application/xml,application/json #触发压缩数据类型
        response:
          enabled: true

5、日志打印功能

日志级别

NONE:默认的,不显示任何日志;

BASIC:仅记录请求方法、URL、响应状态码及执行时间;

HEADERS:除了 BASIC 中定义的信息之外,还有请求和响应的头信息;

FULL:除了 HEADERS 中定义的信息之外,还有请求和响应的正文及元数据。

配置日志类bean

/**
 * 重试机制配置
 */
@Configuration
public class FeignConfig
{
    @Bean
    public Retryer myRetryer()
    {
        return Retryer.NEVER_RETRY; //Feign默认配置是不走重试策略的

        //最大请求次数为3(1+2),初始间隔时间为100ms,重试间最大间隔时间为1s
//        return new Retryer.Default(100,1,3);
    }

    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}

配置yaml开启日志功能

公式(三段):logging.level + 含有@FeignClient注解的完整带包名的接口名+debug

# feign日志以什么级别监控哪个接口
logging:
  level:
    org:
      cloud:
        apis:
          PaymentFeignService: debug