spring boot2.7集成OpenFeign 3.1.7

news2024/11/28 1:00:40

1.Feign

Feign是一个声明式web服务客户端。它使编写web服务客户端更容易。要使用Feign,请创建一个接口并对其进行注释。它具有可插入注释支持,包括Feign注释和JAX-RS注释。Feign还支持可插拔编码器和解码器。Spring Cloud增加了对Spring MVC注释的支持,并支持使用与Spring Web中默认使用的HttpMessageConverters相同的HttpMessageConverters。Spring Cloud集成了Eureka、Spring Cloud CircuitBreaker以及Spring Cloud LoadBalancer,在使用Feign时提供负载均衡的http客户端。

文档地址:https://docs.spring.io/spring-cloud-openfeign/docs/3.1.7/reference/html/#spring-cloud-feign-circuitbreaker

2.创建maven项目spring-cloud-feign-demo

pom.xml配置:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>spring-cloud-feign-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    <modules>
        <module>feign-app1</module>
        <module>feign-app2</module>
    </modules>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <!-- 统一依赖管理 -->
        <spring.boot.version>2.7.8</spring.boot.version>
        <!-- openfeign-->
        <openfeign.version>3.1.7</openfeign.version>
<!--        <openfeign.version>4.0.6</openfeign.version>-->
        <!-- loadbalancer-->
        <loadbalancer.version>3.1.7</loadbalancer.version>
        <!-- hutool工具类-->
        <hutool.version>5.8.11</hutool.version>
        <!-- feign-okhttp-->
        <feign-okhttp.version>11.10</feign-okhttp.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <!-- 统一依赖管理 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring.boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!-- openfeign-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
                <version>${openfeign.version}</version>
            </dependency>
            <!-- loadbalancer-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-loadbalancer</artifactId>
                <version>${loadbalancer.version}</version>
            </dependency>
            <!-- hutool工具类-->
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-all</artifactId>
                <version>${hutool.version}</version>
            </dependency>

            <!-- https://mvnrepository.com/artifact/io.github.openfeign/feign-okhttp -->
            <dependency>
                <groupId>io.github.openfeign</groupId>
                <artifactId>feign-okhttp</artifactId>
                <version>${feign-okhttp.version}</version>
            </dependency>

        </dependencies>

    </dependencyManagement>

</project>

3.创建子项目客户端feign-app1

3.1 pom.xml 配置:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.example</groupId>
        <artifactId>spring-cloud-feign-demo</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>feign-app1</artifactId>
    <packaging>jar</packaging>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>

        <!-- Web 相关 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- openfeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <!-- feign-okhttp-->
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-okhttp</artifactId>
        </dependency>

        <!-- loadbalancer-->
<!--        <dependency>-->
<!--            <groupId>org.springframework.cloud</groupId>-->
<!--            <artifactId>spring-cloud-starter-loadbalancer</artifactId>-->
<!--        </dependency>-->

        <!-- hutool工具类-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
        </dependency>

    </dependencies>

</project>

创建org.example.app1.dto.Store

package org.example.app1.dto;

/**
 * @Version Store v1.0.0 2024/11/25 14:50 $$
 */
public class Store {

    private Long id;
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
}

3.2 创建 org.example.app1.client.StoreClient

package org.example.app1.client;

import org.example.app1.dto.Store;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.util.List;

/**
 * contextId 如果我们想要创建多个具有相同名称或url的虚拟客户端,以便它们指向相同的服务器,但每个客户端都有不同的自定义配置,那么我们必须使用@FeignClient的contextId属性,以避免这些配置bean的名称冲突
 */
@FeignClient(name = "storeClient", url = "${feign.client.config.storeClient.url}")
public interface StoreClient {
    @RequestMapping(method = RequestMethod.GET, value = "/stores")
    List<Store> getStores();

    @RequestMapping(method = RequestMethod.POST, value = "/stores/{storeId}", consumes = "application/json")
    Store update(@PathVariable("storeId") Long storeId, Store store);

    @RequestMapping(method = RequestMethod.DELETE, value = "/stores/{storeId:\\d+}")
    void delete(@PathVariable("storeId") Long storeId);

}


3.3 创建配置文件:org.example.app1.config.StoreClientConfiguration

package org.example.app1.config;

import feign.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

/**
 * @Author tanyong
 * @Version StoreClientConfig v1.0.0 2024/11/25 15:35 $$
 */
@Configuration
public class StoreClientConfiguration {


    /**
     * 要在每个客户端基础上禁用Spring Cloud断路器支持,请创建一个vanilla Feign。具有“prototype”作用域的构建器
     *
     * @return
     */
    @Bean
    @Scope("prototype")
    public Feign.Builder feignBuilder() {
        return Feign.builder();
    }


    /**
     * 默认情况下创建类型为Retryer的NEVER_RETRY,它将禁用重试。
     * 请注意,这种重试行为与Feign默认的行为不同,后者会自动重试ioexception,
     * 将它们视为与网络相关的瞬态异常,以及从ErrorDecoder抛出的任何RetryableException。
     *
     * @return
     */
    // @Bean
    public Retryer feignRetryer() {
        return new Retryer.Default(100, java.util.concurrent.TimeUnit.SECONDS.toMillis(1), 3);
    }
}

3.4 创建org.example.app1.controller.StoreTestController

package org.example.app1.controller;

import org.example.app1.client.StoreClient;
import org.example.app1.dto.Store;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;


/**
 * @Author tanyong
 * @Version StoreController v1.0.0 2024/11/25 14:55 $$
 */
@RestController
public class StoreTestController {

    @Resource
    private StoreClient storeClient;

    @RequestMapping(method = RequestMethod.GET, value = "/stores")
    List<Store> getStores() {
        return storeClient.getStores();
    }

    @RequestMapping(method = RequestMethod.POST, value = "/stores/{storeId}", consumes = "application/json")
    Store update(@PathVariable("storeId") Long storeId, Store store) {

        return storeClient.update(storeId, store);
    }

    @RequestMapping(method = RequestMethod.DELETE, value = "/stores/{storeId:\\d+}")
    void delete(@PathVariable Long storeId) {
        storeClient.delete(storeId);
    }
}

3.5 创建 org.example.app1.interceptor.StoreInterceptor

package org.example.app1.interceptor;

import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.stereotype.Component;

/**
 * @Author tanyong
 * @Version RequestInterceptor v1.0.0 2024/11/26 17:00 $$
 */
@Component
public class StoreInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate template) {
        template.header("Authorization", "Bearer your-token");
    }
}

3.7 创建org.example.app1.DemoApplication1

package org.example.app1;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

/**
 * @Author tanyong
 * @Version DemoApplication1 v1.0.0 2024/11/25 14:30 $$
 */
@SpringBootApplication
@EnableFeignClients
public class DemoApplication1 {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication1.class, args);
    }
}

3.8 application.yaml 配置

spring:
  application:
    name: demo-server1
  main:
    allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。
##############===load-balanced==######################
#    discovery: #服务配置
#      client:
#        simple:
#          instances:
#            stores:
#              - uri: http://localhost:8082


##############===feign配置==######################
feign:
  compression: # GZIP 压缩 spring.cloud.openfeign.okhttp.enabled设置为true时,我们不启用压缩。
    request:
      enabled: true
      mime-types: text/xml,application/xml,application/json
      min-request-size: 2048
    response:
      enabled: true

  autoconfiguration:
    jackson: # 你可以考虑启用Jackson模块来支持org.springframework.data.domain.Page和org.springframework.data.domain.Sort解码
      enabled: true

  lazy-attributes-resolution: true #@FeignClient 延迟解析
  okhttp: #要使用OKHttpClient支持的伪客户端,请确保OKHttpClient在你的类路径中,并将spring.cloud.openfeign.okhttp.enabled设置为true。
    enabled: true
    readTimeout: 5000
  hc5:
    enabled: false #确保HttpClient 5在类路径上
  httpclient:
    enabled: false

  circuitbreaker: #断路由
    enabled: true

  client:
    default-to-properties: false
    config:
      default: #默认配置
        connectTimeout: 1000
        readTimeout: 1000
        loggerLevel: BASIC
      storeClient: #客户端配置,@FeignClient name名称 和 @FeignClient contextId,在负载均衡的场景中,它还对应于将用于检索实例的服务器应用程序的serviceId
        url: http://localhost:8082 #服务的url,该版本不支持此属性,@FeignClient(name = "storeClient", url = "${feign.client.config.storeClient.url}")
        connectTimeout: 5000
        readTimeout: 5000
        loggerLevel: FULL #NONE, No logging (DEFAULT).BASIC, 只记录请求方法和URL以及响应状态代码和执行时间。HEADERS, 标头,记录基本信息以及请求和响应标头。FULL, 记录请求和响应的标头、正文和元数据。
        #errorDecoder: com.example.SimpleErrorDecoder
        #retryer: com.example.SimpleRetryer 默认情况下,使用类型Retryer创建,它将禁用重试。请注意,这种重试行为与Feign默认的行为不同,后者会自动重试ioexception,将它们视为与网络相关的瞬态异常,以及从ErrorDecoder抛出的任何RetryableException
#            defaultQueryParameters: 指定查询参数,这些参数和头将随feignName客户端的每个请求一起发送。
#              query: queryValue
#            defaultRequestHeaders: 指定查询头,这些参数和头将随feignName客户端的每个请求一起发送。
#              header: headerValue
        requestInterceptors: #自定义拦截器
          - org.example.app1.interceptor.StoreInterceptor
#          capabilities:
#            - com.example.FooCapability
#            - com.example.BarCapability
#            queryMapEncoder: com.example.SimpleQueryMapEncoder
#            metrics.enabled: false

server:
  port: 8081


# 日志文件配置
logging:
  level:
    org.example.app1.client: debug

3.9 logback-spring.xml 配置

<configuration>
    <!-- 定义日志文件的存储路径 -->
    <property name="LOG_PATH" value="logs" />
    <property name="LOG_FILE" value="${LOG_PATH}/app.log" />

    <!-- 控制台输出 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} - %level - [%thread] - %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- 文件输出 -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_FILE}</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 每天生成一个新的日志文件 -->
            <fileNamePattern>${LOG_PATH}/app.%d{yyyy-MM-dd}.log</fileNamePattern>
            <!-- 保留最近30天的日志文件 -->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} - %level - [%thread] - %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- 日志级别配置 -->
    <root level="INFO">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="FILE" />
    </root>
</configuration>

4. 创建子项目服务端feign-app2

复制客户端代码,创建org.example.app2.controller.StoreController

package org.example.app2.controller;

import cn.hutool.core.collection.CollUtil;
import org.example.app2.dto.Store;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;


/**
 * @Author tanyong
 * @Version StoreController v1.0.0 2024/11/25 14:55 $$
 */
@RestController
public class StoreController {

    @RequestMapping(method = RequestMethod.GET, value = "/stores")
    List<Store> getStores() {
        Store s = new Store();
        s.setId(1L);
        s.setName("app2");
        return CollUtil.newArrayList(s);
    }

    @RequestMapping(method = RequestMethod.POST, value = "/stores/{storeId}", consumes = "application/json")
    Store update(@PathVariable("storeId") Long storeId, Store store) {
        return store;
    }

    @RequestMapping(method = RequestMethod.DELETE, value = "/stores/{storeId:\\d+}")
    void delete(@PathVariable Long storeId) {

    }
}

5.启动服务

postman调用成功响应:
在这里插入图片描述
客户端打印调用日志:
在这里插入图片描述

简单集成成功,完整配置查看:https://docs.spring.io/spring-cloud-openfeign/docs/3.1.7/reference/html/appendix.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2248727.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于Redis内核的热key统计实现方案|得物技术

一、Redis热key介绍 Redis热key问题是指单位时间内&#xff0c;某个特定key的访问量特别高&#xff0c;占用大量的CPU资源&#xff0c;影响其他请求并导致整体性能降低。而且&#xff0c;如果访问热key的命令是时间复杂度较高的命令&#xff0c;会使得CPU消耗变得更加严重&…

CTF-Hub SQL 报错注入(纯手动注入)

​ 当输入1时&#xff0c;发现只有查询正确&#xff0c;基本上可以判断出没有回显 开始注入(工具hackerBar) 题目是报错注入&#xff0c;方向就比较明显&#xff0c;大致说一下用到的函数和原理。 常见报错注入函数&#xff1a; 通过 floor() 报错注入通过 extractValue() …

Elasticsearch中的节点(比如共20个),其中的10个选了一个master,另外10个选了另一个master,怎么办?

大家好&#xff0c;我是锋哥。今天分享关于【Elasticsearch中的节点&#xff08;比如共20个&#xff09;&#xff0c;其中的10个选了一个master&#xff0c;另外10个选了另一个master&#xff0c;怎么办&#xff1f;】面试题。希望对大家有帮助&#xff1b; Elasticsearch中的节…

linux安装mysql8.0.40

一、下载MySQL安装包 1.查看glibc版本 rpm -qa | grep glibc 2.到mysql官网下载安装包 ​ 二、解压安装 1.上传压缩包纸/usr/local 目录下&#xff0c;解压&#xff1a; tar -xvf mysql-8.0.40-linux-glibc2.17-x86_64.tar.xz 2.重命名&#xff1a; mv mysql-8.0.40-linux-…

【大数据学习 | Spark-Core】RDD的五大特性(包含宽窄依赖)

分析一下rdd的特性和执行流程 A list of partitions 存在一系列的分区列表A function for computing each split 每个rdd上面都存在compute方法进行计算A list of dependencies on other RDDs 每个rdd上面都存在一系列的依赖关系Optionally, a Partitioner for key-value RDDs…

在 Taro 中实现系统主题适配:亮/暗模式

目录 背景实现方案方案一&#xff1a;CSS 变量 prefers-color-scheme 媒体查询什么是 prefers-color-scheme&#xff1f;代码示例 方案二&#xff1a;通过 JavaScript 监听系统主题切换 背景 用Taro开发的微信小程序&#xff0c;需求是页面的UI主题想要跟随手机系统的主题适配…

【C语言】int *p[ ] 与 int (*p)[ ] 的区分辨析

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C语言 文章目录 &#x1f4af;前言&#x1f4af;基本概念&#xff1a;数组与指针&#x1f4af;理解 int *p[10] 与 int (*p)[10]1. int *p[10]&#xff1a;存放指针的数组2. int (*p)[10]&#xff1a;指向数组的指针 …

Vue3 el-table 默认选中 传入的数组

一、效果&#xff1a; 二、官网是VUE2 现更改为Vue3写法 <template><el-table:data"tableData"border striperow-key"id"ref"tableRef":cell-style"{ text-align: center }":header-cell-style"{background: #b7babd…

MT6769/MTK6769核心板规格参数_联发科安卓主板开发板方案

MT6769安卓核心板具有集成的蓝牙、FM、WLAN和GPS模块&#xff0c;是一个高度集成的基带平台&#xff0c;结合了调制解调器和应用处理子系统&#xff0c;以支持LTE/LTE-A和C2K智能手机应用。 该芯片集成了两个工作频率高达2.0GHz的ARMCortex-A75内核、六个工作频率高达1.70GHz的…

在Excel中处理不规范的日期格式数据并判断格式是否正确

有一个Excel表&#xff0c;录入的日期格式很混乱&#xff0c;有些看着差不多&#xff0c;但实际多一个空格少一个字符很难发现&#xff0c;希望的理想格式是 1980-01-01&#xff0c;10位&#xff0c;即&#xff1a;“YYYY-mm-dd”&#xff0c;实际上数据表中这样的格式都有 19…

flask请求头回显的学习和探究如何进行错误页面污染回显

请求头 首先我们要了解一些flask的请求和响应是利用了什么。 flask的请求和响应主要利用了werkzeug&#xff0c;那么我们就要先了解一下什么是werkzeug&#xff0c;其结构又是什么。 werkzeug是一个基于python开发的一个web工具包&#xff0c;其是flask的核心组件之一。其功能…

【Unity踩坑】Unity中父对象是非均匀缩放时出现倾斜或剪切现象

The game object is deformed when the parent object is in non-uniform scaling. 先来看一下现象 有两个Cube, Cube1&#xff08;Scale2,1,1)&#xff0c;Cube2&#xff08;Scale1,1,1&#xff09; 将Cube2拖拽为Cube2的子对象。并且将position设置为&#xff08;-0.6,1,0&a…

uni-app 蓝牙开发

一. 前言 Uni-App 是一个使用 Vue.js 开发&#xff08;所有&#xff09;前端应用的框架&#xff0c;能够编译到 iOS、Android、快应用以及各种小程序等多个平台。因此&#xff0c;如果你需要快速开发一款跨平台的应用&#xff0c;比如在 H5、小程序、iOS、Android 等多个平台上…

解决SSL VPN客户端一直提示无法连接服务器的问题

近期服务器更新VPN后&#xff0c;我的win10电脑一致无法连接到VPN服务器&#xff0c; SSL VPN客户端总是提示无法连接到服务端。网上百度尝试了各种方法后&#xff0c;终于通过以下设置方式解决了问题&#xff1a; 1、首先&#xff0c;在控制面板中打开“网络和共享中心”窗口&…

spring boot框架漏洞复现

spring - java开源框架有五种 Spring MVC、SpringBoot、SpringFramework、SpringSecurity、SpringCloud spring boot版本 版本1: 直接就在根下 / 版本2:根下的必须目录 /actuator/ 端口:9093 spring boot搭建 1:直接下载源码打包 2:运行编译好的jar包:actuator-testb…

大语言模型LLM的微调代码详解

代码的摘要说明 一、整体功能概述 这段 Python 代码主要实现了基于 Hugging Face Transformers 库对预训练语言模型&#xff08;具体为 TAIDE-LX-7B-Chat 模型&#xff09;进行微调&#xff08;Fine-tuning&#xff09;的功能&#xff0c;使其能更好地应用于生成唐诗相关内容的…

华三(HCL)和华为(eNSP)模拟器共存安装手册

接上章叙述,解决同一台PC上同时部署华三(HCL)和华为(eNSP)模拟器。原因就是华三HCL 的老版本如v2及以下使用VirtualBox v5版本,可以直接和eNSP兼容Oracle VirtualBox,而其他版本均使用Oracle VirtualBox v6以上的版本,所以正常安装HCL模拟器无法和ENSP兼容。 环境及组件:…

Android 15 版本更新及功能介绍

Android 15版本时间戳 Android 15,代号Vanilla Ice Cream(香草冰淇淋),是当下 Android 移动操作系统的最新主要版本。 开发者预览阶段:2024年2月,谷歌发布了Android 15的第一个开发者预览版本(DP1),这标志着新系统开发的正式启动。随后,在3月和4月,谷歌又相继推出了D…

【含开题报告+文档+PPT+源码】基于Spring Boot+Vue的在线学习平台的设计与实现

开题报告 随着互联网的普及和技术的快速发展&#xff0c;网络教育逐渐崭露头角&#xff0c;成为现代教育领域的重要组成部分。网络教育以其灵活性、便捷性和资源共享性&#xff0c;吸引了越来越多的学习者。同时&#xff0c;随着学习者需求的多样化&#xff0c;他们对于在线学…

【Flink】快速理解 FlinkCDC 2.0 原理

快速理解 FlinkCDC 2.0 原理 要详细理解 Flink CDC 原理可以看看这篇文章&#xff0c;讲得很详细&#xff1a;深入解析 Flink CDC 增量快照读取机制 (https://juejin.cn/post/7325370003192578075)。 FlnkCDC 2.0&#xff1a; Flink 2.x 引入了增量快照读取机制&#xff0c;…