news 2026/9/8 1:27:13

Spring Profiles active与include实战:多环境配置优先级与最佳实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring Profiles active与include实战:多环境配置优先级与最佳实践

1. 先搞明白:Spring Profiles 到底帮你解决了什么问题

接触过实际项目的朋友应该都有感触,配置文件才是项目里最容易出幺蛾子的地方。开发环境连本地数据库,测试环境连测试库,生产环境要连主库,一个项目少则两套配置多则五六套。以前没有 Profiles 的时候,大家就硬改 application.properties,改完上线忘了改回来,结果把测试环境的数据写进了生产库,这种事我见过不止一次。

Spring Profiles 的本质,就是给不同的运行环境打标签。你可以在 Spring Boot 的 application.yml 或 application.properties 中为不同环境定义不同的配置片段,然后通过激活某个或某几个 Profile,告诉 Spring "当前环境我只要这些配置"。它解决的痛点是三个:一是环境隔离,二是配置复用,三是行为开关。

但另一个常见问题是,随着微服务拆分、基础组件增多,"一个环境对应一套配置"这个模型慢慢不够用了。有时候你的数据库配置和生产环境绑定,但消息队列配置却和公共模块绑定;有时候你有一个公共的监控配置,不管哪个环境都要加载;有时候你又希望某个 Profile 在激活另一个 Profile 时被顺带激活。这时候光靠 spring.profiles.active 就捉襟见肘了,于是就有了 spring.profiles.include。

文章里我不会讲太深奥的源码,重点就是这两个配置项到底怎么用、区别在哪、优先级顺序怎么排、实际项目里怎么搭配。

2. spring.profiles.active 和 spring.profiles.include 的本质区别

2.1 一句话先记下两者定位

spring.profiles.active 是从外部指定当前环境,它代表的是"入口"和"主导"。

spring.profiles.include 是在当前配置文件中主动声明"我还需要哪些附加 Profile",它代表的是"附加"和"组合"。

这两者最直观的现象是:spring.profiles.active 可以通过启动参数、环境变量、JVM 系统属性、命令行参数等方式外部覆盖,而 spring.profiles.include 基本只能在配置文件里写死。

用一个生活化的类比来说:spring.profiles.active 很像你出门前决定"今天我是上班族身份",这个身份决定了你基本的行为模式;而 spring.profiles.include 很像你在这个身份基础上还要叠加"今天我是健身房会员"、"今天我是要去银行办事的人"这些附加身份。主身份由外部情境决定,附加身份由你自己补充。

2.2 active 和 include 在配置加载顺序上的差异

这是很多人在踩的坑。Spring Boot 在加载配置时,并不是简单地先加载 active 指定的文件,再加载 include 指定的文件,顺序是反过来的。

实际加载顺序是:先加载 spring.profiles.include 引入的 Profile 配置,再加载 spring.profiles.active 指定的 Profile 配置。

也就是说,相同配置项下,spring.profiles.active 的优先级高于 spring.profiles.include。Spring Boot 官方文档有一句很关键的说明:spring.profiles.include 中的 Profile 会在 active 之前被处理。这意味着如果同一属性在 active Profile 和 include Profile 中都定义了,active 的值会覆盖 include 的值。

打个比方:include 好比是"基础包",active 好比是"个性定制",定制的内容永远覆盖基础包的内容。我在实际项目中就遇到过这样的问题:公共监控配置放在 include 的 common Profile 里,但为了调试临时把日志级别调成 DEBUG 写在 active 的 dev Profile 里,结果发现日志级别没生效,后来排查才知道是配置项被 include 里的配置覆盖了。当时就是没搞清楚这个加载顺序。

2.3 active 的多种外部注入方式,优先级从高到低

spring.profiles.active 最大的价值是支持外部注入。Spring Boot 的配置优先级本身就遵循一套非常复杂的规则,从命令行参数到 JVM 系统属性、再到环境变量、再到 application-{profile}.properties 配置文件,逐层覆盖。就 spring.profiles.active 而言,常见的注入方式有:

  • 命令行参数:--spring.profiles.active=prod,这是优先级最高的方式,适合部署脚本传入。
  • JVM 系统属性:-Dspring.profiles.active=prod,适合启动脚本设置。
  • 环境变量:SPRING_PROFILES_ACTIVE=prod,适合容器化部署时在 Docker/K8s 中注入。
  • 配置文件里的spring.profiles.active=prod,适合本地开发或默认值场景。

命令行参数最优先,其次是 JVM 系统属性,再次是环境变量,最后是配置文件里的值。这个优先级顺序在官方文档中描述得很清楚。

投影到实际场景:本地开发时你在 application.properties 里写死 spring.profiles.active=dev,到了部署环节,运维的启动脚本传了 --spring.profiles.active=prod,那么这个命令行参数会覆盖配置文件里的值。如果你在配置文件中没有写 active,但环境变量里有 SPRING_PROFILES_ACTIVE=prod,则会使用环境变量的值。

2.4 include 为什么不能外部覆盖?其实是设计如此

很多人问过:include 能不能像 active 一样用启动参数指定?答案是:不能。spring.profiles.include 是配置文件的内部声明,Spring Boot 在设计时就没打算让它被外部覆盖。

为什么?从职责来看,include 天然适合表达"当前配置模块组合"... 如果 include 可以被外部覆盖,那配置组合就完全由运维说了算,开发预期的"基础模块组合"就形同虚设了。这违背了 include 的设计目的:它要保证某些 Profile 无论什么环境下都生效,除非显式指定另一个 Profile 组合。

不过这里有个细节需要说清楚:spring.profiles.include 可以在不同的配置文件中分别声明。什么意思呢?比如 application-dev.properties 里声明 spring.profiles.include=common,monitor,application-prod.properties 里声明 spring.profiles.include=common,audit。当激活 dev 时,加载的是 common 和 monitor;当激活 prod 时,加载的是 common 和 audit。这样 include 也能有一定的环境差异,但它的依据是"你是通过 active 进来的",而不是外部直接传进来的。

3. 实际项目里 include 的典型使用场景

3.1 场景一:公共模块拆分

假设一个项目有数据库、Redis、MQ、日志、监控这几个模块。如果每个环境的 active Profile 里都把这几个模块的配置写一遍,会产生大量重复代码,而且一改配置就要改多个文件。

我的做法是拆分为:

  • application-common.properties:公共配置,比如通用连接池参数、通用超时时间、通用日志格式。
  • application-db.properties:数据库相关配置。
  • application-mq.properties:消息队列相关配置。
  • application-monitor.properties:监控相关配置。

然后在 application-dev.properties 里配置spring.profiles.include=common,db,mq,monitor,application-prod.properties 里同样配置spring.profiles.include=common,db,mq,monitor,不同的环境再覆盖一些差异化配置项。这样一目了然,哪些模块是公共的,哪些环境有特殊覆盖,非常清晰。

这个模式其实很像组件化的思想:把系统拆成几个可组合的配置块,然后用 include 把它们组合起来。

3.2 场景二:局部模块的按需启停

还有一种场景是某个功能模块不是所有环境都需要。比如灰度环境需要开启流量复制模块,但生产环境不需要。这种情况下:

  • application-gray.properties 里配置spring.profiles.include=common,replicator
  • application-prod.properties 里只配置spring.profiles.include=common

activ=gray 时流量复制模块生效,active=prod 时不生效,而且生产环境配置文件中根本看不到与流量复制相关的敏感配置。这种做法既保证了组合的灵活性,也降低了误操作风险。

3.3 场景三:多个 Profile 叠加时的配置优先级梳理

实际项目中往往不会只有一个 active。比如--spring.profiles.active=dev,dev-detail,这表示同时激活 dev 和 dev-detail。这种情况下,dev-detail 中如果包含和 dev 相同的配置项,哪个生效?

这里要注意,多个 active 之间不是简单的先后关系。Spring Boot 对多 Profile 激活的处理是:后面声明的 Profile 优先级更高。所以 --spring.profiles.active=dev,dev-detail 中,dev-detail 的配置优先级高于 dev。

而 include 里的 Profile 会在所有 active 之前加载。所以整体优先级从低到高是:include 引入的 Profile < 先声明的 active Profile < 后声明的 active Profile。

这个优先级规则在生产环境调试时非常有用。比如你想在 dev 环境临时加一个特殊配置,又不想改动公共配置,就可以额外指定一个 --spring.profiles.active=dev,dev-temp,然后在 application-dev-temp.properties 中覆盖需要的配置项,完全不影响 dev 原有的配置。

4. 多 Profile 文件命名规则与加载机制

4.1 命名规则回顾:application-{profile}.properties

要理解 include 和 active 的作用,必须得先搞清楚 Profile 文件的加载机制。

Spring Boot 默认加载文件名是 application.properties 或 application.yml。当激活某个 Profile 时,它会额外加载 application-{profile}.properties 或 application-{profile}.yml。

比如 spring.profiles.active=dev,Spring Boot 会去找 application-dev.properties;如果同时激活了 dev 和 test,则会加载 application-dev.properties 和 application-test.properties。

你没有在配置文件中声明的 Profile,比如直接放一个 application-xxx.properties 在 classpath 下,但没激活 xxx,Spring Boot 不会自动加载它。Profile 必须被"激活"才会生效,激活手段主要是 active 和 include。

这里有个容易忽略的细节:include 指定的 Profile,同样会遵循这个命名规则。比如 spring.profiles.include=common,Spring Boot 会去加载 application-common.properties。如果这个文件不存在,会发生什么?这里先留个悬念,后面在常见问题里细说。

4.2 YAML 与 Properties 的差异

如果你的项目用的是 YAML 而不是 Properties,情况会有一些细微的差别。

在 YAML 中,一个文件里可以通过---分隔多个文档块,每个块可以指定自己的 spring.config.activate.on-profile。这种写法的实际效果和使用多个 application-{profile}.yml 文件类似。

而 spring.profiles.active 和 spring.profiles.include 的语义是不分 YAML 和 Properties 的,完全一致。唯一的注意点是:如果你在单个 YAML 文件中用多文档块来组织 Profile,那么 spring.profiles.include 写在哪个文档块里,只对哪个文档块生效。这点和 Properties 文件中的"全局生效"有一些微妙差异。

举个例子:

spring: profiles: dev profiles: include: common,monitor

这个写法在旧版本中可能被解析成 spring.profiles 的配置,但在 Spring Boot 2.4+ 之后,spring.profiles这个属性被废弃,取而代之的是spring.config.activate.on-profile。所以在高版本 Spring Boot 中,YAML 里的多文档块现在推荐这样写:

spring: config: activate: on-profile: dev

include 的写法不变,依然是spring.profiles.include

这里引出一个大坑:在 Spring Boot 2.4 之前和之后,配置文件的加载逻辑发生了重大变化,这直接影响 include 的行为。下面来细说。

4.3 Spring Boot 2.4 前后的行为差异

Spring Boot 2.4 对配置文件的加载机制做了一次较大的重写,最直接的影响有两个:

第一个影响是:不再支持从application-{profile}.properties中读取 spring.profiles.active 来激活其他 Profile。什么意思?在 2.4 之前的版本,你可以在 application-dev.properties 中写 spring.profiles.active=dev-extra,然后 dev 被激活时 dev-extra 也会被激活。但在 2.4+ 中,这个机制被移除了,官方建议改用 spring.profiles.include 或 spring.profiles.group。

第二个影响是:spring.profiles.include 的优先级和加载顺序在 2.4+ 中有了一些调整,但 "include 先加载,active 后加载" 这个核心顺序仍然保留。官方文档对此有明确说明。

还有一个重要概念是 spring.profiles.group。这个属性在 2.4+ 中引入,目的是解决 include 的一个痛点:include 只能在配置文件中写死,而 group 可以更灵活地组合多个 Profile。

5. spring.profiles.group 与 include 的组合使用

5.1 group 是 include 的升级版

spring.profiles.group 的定义方式如下:

spring.profiles.group.prod=prod-db,prod-mq,common

这段配置的意思是:定义了一个名为 prod 的 Profile 组,它包含 prod-db、prod-mq、common 三个成员 Profile。当激活 prod 时,这三个成员 Profile 会被自动激活。

与 include 相比,group 的优势在于:它把"组合关系"集中定义在独立的地方,而不是分散在每个环境配置中。当你有很多环境、很多公共模块时,group 的集中管理优势非常明显。

而且 group 的优先级高于 include,也就是说如果同时使用 group 和 include,Spring Boot 会先处理 group 的成员激活逻辑,再处理 include 的激活逻辑。group 中定义的成员 Profile 会在 include 的 Profile 之前被处理?这里我又需要谨慎一些——实际上 Spring Boot 的文档并没有给出非常明确的 group 与 include 相对优先级说明,但从源码实现中来看,group 的展开是在 Profile 激活阶段,include 则是在配置文件加载阶段,两者的实际生效顺序存在版本差异。

为了稳妥,我自己的实践经验是:group 和 include 不要混用。要么全靠 include 组合,要么全靠 group 组合。混用时出现优先级问题排查成本很高。

5.2 什么时候用 group,什么时候用 include?

如果你的项目是 Spring Boot 2.4+,并且 Profile 组合关系相对固定、且需要集中管理,推荐用 spring.profiles.group。

如果你的项目还在使用 Spring Boot 2.4 之前的版本,或者你的 include 是分散在各个环境配置中的,那维持 include 就好。

从团队协作角度来看,我也更推荐 group。因为 include 的写法天然会让人困惑:到底是先加 include 再激活,还是先激活再 include?而 group 的语义非常明确:这是一个组,激活这个组等于激活这些成员。

5.3 group 的配置示例与实际效果

我举个真实例子,一个典型的微服务项目包含以下 Profile:

common(公共配置)、db-dev(开发库)、db-prod(生产库)、mq-dev(开发队列)、mq-prod(生产队列)、monitor(监控)、audit(审计)

使用 group 配置:

spring.profiles.group.dev=common,db-dev,mq-dev,monitor spring.profiles.group.prod=common,db-prod,mq-prod,monitor,audit spring.profiles.group.test=common,db-dev,mq-dev,monitor

启动时只需要指定 --spring.profiles.active=dev 或 prod,不需要写一大串 Profile 名称。这个可读性和维护性比直接在启动命令里列一堆 Profile 要清晰得多。

需要注意 group 的定义文件本身,如果写在 application.properties 中,则对所有环境生效;如果写在 application-dev.properties 中,则只有当 dev 被激活时这些 group 定义才可见。我建议把 group 定义统一放在主配置文件中,避免分散。

6. 核心实操:一个完整的多环境配置改造案例

6.1 改造前的现状与问题

假设有一个老项目,配置结构如下:

  • application.properties:主配置
  • application-dev.properties:开发环境配置
  • application-prod.properties:生产环境配置

每个环境配置文件中都大量重复定义了数据源、Redis、MQ 等配置。开发改一个公共参数,比如连接池最大连接数,就得同时改多个文件。更重要的是,新接手的同事经常搞不清楚到底哪个配置在生效。

改造目标:抽取公共配置,统一管理 Profile 组合,尽量降低配置文件维护成本。

6.2 改造步骤详解

第一步,把公共配置抽取出来。

从 dev 和 prod 配置中找到不随环境变化的配置项,比如 RocketMQ 的 producer 组名、公共的线程池参数、监控上报地址等,放入 application-common.properties。

第二步,把差异化配置按环境保留。

数据库 URL、Redis 地址等随环境变化的配置,保留在 application-dev.properties 和 application-prod.properties 中。

第三步,在环境配置中声明 include。

application-dev.properties 中添加:

spring.profiles.include=common

application-prod.properties 中添加:

spring.profiles.include=common,audit

第四步,启动验证。

使用 --spring.profiles.active=dev 启动,观察控制台输出,确认加载了 application-common.properties 和 application-dev.properties。

6.3 改造后遇到的一个优先级问题

这里分享一个我改造过程中踩过的真实坑。

抽取公共配置后,连接池的配置如下:

  • application-common.properties 中配置了spring.datasource.hikari.maximum-pool-size=10
  • application-dev.properties 中配置了spring.datasource.hikari.maximum-pool-size=5

我预期结果是 dev 环境使用 5,结果启动后 HikariCP 的连接池大小是 10。

原因正是 include 的加载顺序:include 的 Profile(common)先加载,active 的 Profile(dev)后加载,后加载的同名配置项应该覆盖先加载的。那为什么 dev 的值没生效?

排查后发现,问题不在 include,而在配置文件的覆盖顺序。Spring Boot 加载配置时遵循 "profile-specific 配置覆盖默认配置" 的规则,默认 application.properties 的值被 application-common.properties 覆盖,application-common.properties 的值被 application-dev.properties 覆盖——这个规则本身没错。但如果 application-dev.properties 中的配置项拼写有细微错误,比如写成了 max-pool-size 而不是 maximum-pool-size,Spring Boot 不会报错,它只是不识别这个属性,后面加载的同名属性就不会覆盖前面的值。

所以排查优先级问题时,第一件事不是怀疑 include 和 active 的顺序,而是先用--debug参数启动,查看实际生效的配置来源。Spring Boot 在 debug 模式下会打印出配置的来源信息,哪个文件、哪个属性、哪个优先级,一目了然。

6.4 配置生效验证小技巧

分享一个非常实用的验证方法:写一个简单的 ApplicationRunner 或 CommandLineRunner,在启动时打印关键配置值。

@Component public class ConfigPrinter implements ApplicationRunner { @Value("${spring.datasource.hikari.maximum-pool-size}") private String poolSize; @Override public void run(ApplicationArguments args) { System.out.println(" ====== poolSize: " + poolSize); for (String profile : Environment.getActiveProfiles()) { System.out.println(" ====== active profile: " + profile); } } }

这个办法在排查 include、active、group 组合问题时非常好用。通过 Environment.getActiveProfiles() 可以直观看到当前到底激活了哪些 Profile,避免"我以为激活了 A,其实还带着 B"的误判。

7. 常见问题与速查表

7.1 include 指定的 Profile 文件不存在会怎样?

先说结论:如果 spring.profiles.include 指定的 Profile 在配置文件加载时没有对应文件,Spring Boot 不会报错。它只是简单地跳过这个 Profile 的属性加载。

但这里有个细思极恐的坑:如果这个 Profile 里定义了一个 bean,比如 @Configuration 类上标注了 @Profile("common"),但 common 这个 Profile 因为配置文件不存在而没有被正确激活,那么这个 bean 就不会被注册。如果你在 include 中写了 common,却又没有 application-common.properties 文件,Spring Boot 的控制台可能不会出现明显的报错,但你的某个功能就是起不来。

所以我的建议是:include 的 Profile 一定要保证有对应的配置文件,哪怕文件里只有一行注释。养成这个习惯,能避免很多深水炸弹。

7.2 为什么 spring.profiles.include 不生效?

排查思路按以下顺序:

第一,确认 Spring Boot 版本。2.4 之前和 2.4 之后的行为有差异,老项目中 include 的用法在新版本中可能失效。

第二,确认 include 写在哪个文件中。include 写在 application.properties 中,则全局生效;写在 application-dev.properties 中,则只有 dev 激活时生效。如果 dev 本来就没被激活,你写在 application-dev.properties 中的 include 当然不会生效。

第三,确认拼写。spring.profiles.include 还是 spring.profiles.includes?很多人会写错,多写一个 s。

第四,确认是否与 group 混用且发生了预期外的覆盖关系。如果同时配置了 spring.profiles.group 和 spring.profiles.include,建议先临时删掉 group 验证,一步步缩小范围。

7.3 active 和 include 同时配置同名属性,到底谁的生效?

前面已经说过了,include 的 Profile 先于 active 的 Profile 加载,因此 active 同名属性覆盖 include 同名属性。

举个例子:

  • application-common.properties:app.name=common-name
  • application-dev.properties:app.name=dev-name
  • application.properties:spring.profiles.active=dev, spring.profiles.include=common

最终生效的是 dev-name。

如果把顺序反过来,spring.profiles.active=common,然后 dev 通过 include 引入,那最终生效的是 common-name。也就是说,决定优先级的是 Profile 的"加载顺序",而不是你在 active 中写了几个 Profile。这个点非常容易搞混,需要刻在脑子里。

7.4 常见问题速查表

症状可能原因处理方法
include 的配置没生效include 写在非全局配置文件中,且该 Profile 未激活检查 include 所在的文件和当前激活的 Profile 组合
active 的配置被覆盖include 中同名配置项的加载顺序在 active 之前确认优先级规则,调整配置归属文件
代码里 @Profile("xxx") 的类没有加载xxx Profile 未激活,或 include 引入了不存在的 Profile用 Environment.getActiveProfiles() 打印确认
Spring Boot 2.4 下 include 失效项目从旧版本升级,加载机制已变更改用 spring.profiles.group
某个环境配置始终是旧值配置文件拼写错误或属性未被识别使用 --debug 启动,查看配置来源

8. 我的经验总结:这些配置习惯值得长期坚持

我见过很多项目组在 Profile 的使用上陷入混乱,核心原因不是技术不会,而是没有提前约定好使用规范。从我自己的实操体验出发,有几点想分享给大家参考。

第一,把"入口配置"和"附加配置"分开管理。spring.profiles.active 只负责指定主环境,spring.profiles.include 只负责声明公共模块和附加模块。不要让一个配置既承担入口职责又承担附加职责,否则排查时逻辑会很拧巴。

第二,多环境配置尽量采用"公共配置 + 环境差异"的模式。公共配置放在 application-common.properties 中,环境差异配置放在 application-{env}.properties 中,环境配置里用 include 引入 common。这套模式在微服务项目里我已经验证过很多次,维护成本低,新同事上手快。

第三,Spring Boot 2.4+ 的新项目,建议直接用 spring.profiles.group 替代 include 作为主要组合手段。group 的优势在于集中定义、语义清晰,尤其适合 Profile 数量较多的项目。

第四,定期用启动日志排查配置来源。每次人员变动、配置调整后,留意启动时的 Profile 激活日志,确认没有意外加载的 Profile。这比出问题后再去排查要划算得多。

配置管理这件事,投入产出比非常高。花半天时间把 Profile 结构理清楚,后面每次发布、每次调参都能省下大把时间。这套东西不复杂,但用好了能让项目的配置维护变得轻松很多。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 1:27:09

vSphere SDK 6.0.0实战:pyVmomi环境配置、自动化操作与踩坑指南

简介&#xff1a;VMware vSphere Management SDK 6.0.0 是面向虚拟化平台开发者的集成开发套件&#xff0c;包含 vSphere Web Services SDK、Storage Management SDK、ESX Agent Manager SDK、SSO Client SDK 与 Storage Policy SDK&#xff0c;适用于需要构建虚拟机管理工具、…

作者头像 李华
网站建设 2026/9/8 1:25:36

Servlet与web.xml配置详解:从原理到实战踩坑

刚接触Java Web的时候&#xff0c;我最怕的不是写Servlet代码&#xff0c;而是配web.xml。明明核心逻辑就在那个doGet方法里&#xff0c;可每次部署到Tomcat都卡在配置上——要么servlet-name对不上&#xff0c;要么url-pattern少了斜杠&#xff0c;页面直接甩我一个404&#x…

作者头像 李华
网站建设 2026/9/8 1:24:43

公司充值ChatGPT服务支付方式系统指南

2026年AI技术在企业场景的应用持续深化&#xff0c;中泰证券《Token 经济学&#xff1a;AI 时代的新生产要素与产业重构》研究显示&#xff0c;Token已成为AI时代核心生产要素与价值载体&#xff0c;企业在ChatGPT等大模型API调用、AI工具订阅、算力采购等方面的支出规模快速增…

作者头像 李华
网站建设 2026/9/8 1:24:33

毕业设计全程AI工具链:从论文写作到代码开发的实战组合

每年到毕业季前后&#xff0c;我总能收到大量学弟学妹的私信&#xff0c;问的无外乎是“论文怎么写才能不被导师连环打回”“毕业设计的系统到底怎么搭”“代码跑不通怎么办”。说实话&#xff0c;过去几年大家还在靠纯手工肝文档、熬夜调代码&#xff0c;但今年这批人手里已经…

作者头像 李华
网站建设 2026/9/8 1:23:26

nvCOMP实战指南:用GPU将压缩吞吐提升一个量级

做数据处理和存储这行的朋友&#xff0c;对LZ4、Snappy、Zstd这些压缩库应该都不陌生。但如果你接触过大规模数据的在线导入、列式存储落盘&#xff0c;或者AI训练前的数据预处理链路&#xff0c;大概率会遇到一个尴尬场景&#xff1a;CPU核数堆得很高&#xff0c;压缩吞吐还是…

作者头像 李华