# z2huo-framework **Repository Path**: z2huo/z2huo-framework ## Basic Information - **Project Name**: z2huo-framework - **Description**: 统一管理依赖版本并封装 Spring Boot Starter 的公共框架。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-11 - **Last Updated**: 2026-10-22 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # z2huo-framework 公共框架 ## 一、定位 统一管理依赖版本并封装 Spring Boot Starter 的公共框架。业务项目只需 import 一个 BOM,或继承一个 parent,即可获得 Java、Web、微服务、可观测等方向的依赖版本对齐与开箱能力。 当前状态:已从 spring-boot-demo 仓库迁出,作为独立仓库维护,本仓库根目录即框架根目录。spring-boot-demo 等业务仓库通过本地仓库或私服消费 `cn.z2huo.framework` 坐标,构建前需先在本仓库执行 `mvn clean install`。 ## 二、目录与坐标 | 模块 | 坐标 | 形态 | 用途 | | -------------------------------------- | --------------------------------------------------------- | ----------- | ------------------------------------------------ | | `z2huo-framework` | `cn.z2huo.framework:z2huo-framework` | 根聚合 | 构建插件栈、构建期属性、flatten | | `z2huo-framework-dependencies` | `cn.z2huo.framework:z2huo-framework-dependencies` | BOM | 版本属性与 `dependencyManagement` 的单一权威 | | `z2huo-framework-parent` | `cn.z2huo.framework:z2huo-framework-parent` | 应用 parent | 继承 `spring-boot-dependencies`,复刻应用侧构建约定 | | `z2huo-framework-common` | `cn.z2huo.framework:z2huo-framework-common` | 工具库 + 契约 | 雪花 ID、状态码、异常、统一信封 `ApiResult` / `PageData` / `PageCondition`、共享 `RedisJsonMapper` | | `z2huo-framework-starter` | `cn.z2huo.framework:z2huo-framework-starter` | 配置模板 + 工具类 | 4 个 logback 入口 + 5 个片段、`SpringBeanUtils` | | `z2huo-framework-starter-web` | 同规则 | 依赖聚合 + 自动配置 | Web + 校验依赖,自动注册全局异常处理器 | | `z2huo-framework-starter-test` | 同规则 | 纯依赖聚合 | 传递 `spring-boot-starter-test` | | `z2huo-framework-starter-redis` | 同规则 | 配置模板 + 自动配置 | Lettuce 集群配置与 JSON 序列化 `RedisTemplate` | | `z2huo-framework-starter-redisson` | 同规则 | 配置模板 + 自动配置 | Redisson 集群配置与统一 codec | | `z2huo-framework-starter-cache` | 同规则 | 配置模板 + 自动配置 | JetCache 两级缓存 + 独立 Caffeine 工具 | | `z2huo-framework-starter-druid` | 同规则 | 纯配置模板 | Druid 连接池与监控页默认配置 | | `z2huo-framework-starter-hikaricp` | 同规则 | 纯配置模板 | HikariCP 连接池默认配置 | | `z2huo-framework-starter-mybatis-plus` | 同规则 | 配置模板 + 自动配置 | MyBatis-Plus ORM 配置,注册分页拦截器与框架雪花发号 | | `z2huo-framework-starter-mybatis-plus-join` | 同规则 | 纯依赖聚合 | 在 MP starter 之上叠加 mybatis-plus-join 连表能力 | | `z2huo-framework-starter-skywalking` | 同规则 | 纯依赖聚合 | SkyWalking toolkit;agent 需另行挂载 | | `z2huo-framework-starter-dubbo` | 同规则 | 纯依赖聚合 + 配置模板 | Dubbo 官方集成与 Nacos 注册适配,Sentinel 桥接为 optional | | `z2huo-framework-starter-nacos-config` | 同规则 | 纯依赖聚合 + 配置模板 | Nacos 配置中心适配,不含服务注册与发现 | | `z2huo-framework-starter-nacos-discovery` | 同规则 | 纯依赖聚合 + 配置模板 | Nacos 服务注册与发现适配,不含配置中心 | | `z2huo-framework-starter-sentinel` | 同规则 | 配置模板 + 自动配置 | Sentinel 单机限流 + Nacos 规则源 + 统一拦截应答 | | `z2huo-framework-examples` | 同规则 | 验证示例聚合 | 各 starter 的可运行验证示例,不作为库发布 | 约定:`groupId` 固定 `cn.z2huo.framework`,Java 包根固定 `cn.z2huo.framework.core`,配置属性前缀固定 `z2huo.`。 starter 附带的配置模板统一放在各自 `src/main/resources` 的**根目录**,命名规则为: - 属于 Spring 配置文档的,名字形如 `application-z2huo-<领域>[-变体].yaml`。必须带 `application-` 前缀,因为 IntelliJ IDEA 只对根目录下以 `application` 开头的 yaml 做属性补全(子目录里的 `application-*.yaml` 不提示);`z2huo-` 中段是为了占用唯一命名空间、同时消除 jar 间同名。 - 不属于 Spring 配置文档的(如 Redisson 原生格式的 `z2huo-redisson-cluster.yaml`,由 `spring.redis.redisson.file` 指向),刻意不带 `application-` 前缀,避开被当成配置文档解析。 为什么中段必须长:Spring Boot 会在 `classpath:/` 与 `classpath:/config/` 两个标准位置搜索 profile 专属文档,因此 jar 根目录里任何 `application-.yaml` 都会在有人激活名为 `X` 的 profile 时被**自动加载**,不需要任何 `spring.config.import`(已实测:jar 根目录的 `application-probe.yaml` 在 `--spring.profiles.active=probe` 下直接生效)。`z2huo-` 前缀把需要撞上的 profile 名抬到实践上不会出现的长度。同理,模板绝不能放进 `config/` 目录。 ## 三、接入方式 ### 1、方式 A,import BOM 适合只想拿版本对齐、构建插件与资源过滤自己管的项目(例如已经自行继承 `spring-boot-starter-parent` 的应用)。 注意 `import` 只带来 `dependencyManagement`,不带来 `pluginManagement`:走本方式的项目需自行声明 `maven-compiler-plugin`、`spring-boot-maven-plugin` 等插件版本,以及 `application*` 资源的 `@` 分隔符过滤(若用到 `spring.application.name=@application.name@` 这类写法)。 ```xml cn.z2huo.framework z2huo-framework-dependencies 0.1.0 pom import ``` ### 2、方式 B,继承应用 parent 适合希望一行完成接入的新应用。本模块直接以 `spring-boot-dependencies` 为父 POM(与 `spring-boot-starter-parent` 同一做法),因此 29 个常用构建插件的版本与全部依赖版本都由 Boot 统一供给;在此基础上只复刻 starter-parent 中实际被用到的约定: - `application*.yml|yaml|properties` 参与资源过滤(分隔符仅 `@`,`useDefaultDelimiters=false`)。 - `maven-compiler-plugin` 的 `true`。 - `maven-jar-plugin` 写 `Implementation-Title` / `Implementation-Version`(Actuator `/info` 读它)。 - `spring-boot-maven-plugin` 的 `repackage` 执行与 `mainClass`(仅在 `pluginManagement` 中定义,应用自己声明才生效)。 - `maven-failsafe-plugin` 的 `integration-test` / `verify` 绑定。 Kotlin、WAR、native、git-commit-id、cyclonedx 以及 `native` / `nativeTest` profile 等未被使用的配置均已剔除。代价是 Boot 升版时需人工比对新版本 starter-parent 是否新增了需要跟进的构建约定。 ```xml cn.z2huo.framework z2huo-framework-parent 0.1.0 ``` ### 3、声明依赖 两种方式下,业务依赖都不写版本号。 ```xml cn.z2huo.framework z2huo-framework-starter-web ``` ## 四、各 starter 的 jar 内资源与接入动作 | 模块 | jar 内资源 | 接入必需动作 | 详细文档 | | ------------------------------------ | ------------------------------------------------------------- | ----------------------------------------------------------------------------- | --------------------------------------------------------------- | | `z2huo-framework-starter` | 4 个 logback 入口 + 5 个片段 | 引依赖即生效;换日志变体需设 `logging.config` | [README](z2huo-framework-starter/README.md) | | `z2huo-framework-starter-web` | 无配置模板(只有 `META-INF/spring` 下的自动配置登记件) | 引依赖即自动注册 `GlobalExceptionHandler`;不想要时置 `z2huo.web.exception-handling.enabled=false` | [README](z2huo-framework-starter-web/README.md) | | `z2huo-framework-starter-test` | 无 | `test` 引入 | 无,见第二节说明 | | `z2huo-framework-common` | 无 | 引依赖,直接 import 工具类与 `ApiResult` / `PageData` / `PageCondition` | 契约细则见 starter-web README | | `z2huo-framework-starter-redis` | `application-z2huo-redis-cluster.yaml` | `spring.config.import` 导入 + 覆盖集群地址 | [README](z2huo-framework-starter-redis/README.md) | | `z2huo-framework-starter-redisson` | `application-z2huo-redisson.yaml` + `z2huo-redisson-cluster.yaml` | `spring.config.import` 导入 `application-z2huo-redisson.yaml` | [README](z2huo-framework-starter-redisson/README.md) | | `z2huo-framework-starter-cache` | `application-z2huo-jetcache.yaml` + `application-z2huo-caffeine.yaml` | `spring.config.import` 导入 `application-z2huo-jetcache.yaml`,它已连带导入 redisson 配置 | [README](z2huo-framework-starter-cache/README.md) | | `z2huo-framework-starter-druid` | `application-z2huo-datasource.yaml` | `spring.config.import` 导入 + 覆盖 url | [README](z2huo-framework-starter-druid/README.md) | | `z2huo-framework-starter-hikaricp` | `application-z2huo-datasource.yaml` | 同上,与 druid 二选一 | [README](z2huo-framework-starter-hikaricp/README.md) | | `z2huo-framework-starter-mybatis-plus` | `application-z2huo-mybatis-plus.yaml` | `spring.config.import` 导入 ORM 模板 + 连接池模板,另需自写 `@MapperScan` | [README](z2huo-framework-starter-mybatis-plus/README.md) | | `z2huo-framework-starter-mybatis-plus-join` | 无(依赖核心 MP starter,模板由它提供) | 同上(传递依赖 MP starter,无需再单独引) | [README](z2huo-framework-starter-mybatis-plus-join/README.md) | | `z2huo-framework-starter-skywalking` | 无(模块目录下另有 `skywalking.vmoptions` 模板,不进 jar) | 引依赖后必须补 `-javaagent` 等 JVM 启动参数 | [README](z2huo-framework-starter-skywalking/README.md) | | `z2huo-framework-starter-dubbo` | `application-z2huo-dubbo.yaml` | `spring.config.import` 导入 dubbo 模板;需限流时另引 sentinel starter 并追加导入它的模板 | [README](z2huo-framework-starter-dubbo/README.md) | | `z2huo-framework-starter-nacos-config` | `application-z2huo-nacos-config.yaml` | `spring.config.import` 按序导入本模板与 `optional:nacos:`,地址与命名空间自己注入 | [README](z2huo-framework-starter-nacos-config/README.md) | | `z2huo-framework-starter-nacos-discovery` | `application-z2huo-nacos-discovery.yaml` | `spring.config.import` 导入本模板即可,无需 `nacos:` 导入 | [README](z2huo-framework-starter-nacos-discovery/README.md) | | `z2huo-framework-starter-sentinel` | `application-z2huo-sentinel.yaml` | `spring.config.import` 导入本模板 + 按环境注入 Nacos 与控制台地址;需 HTTP 统一拦截应答再引 starter-web(拿它的 servlet 栈,`ApiResult` 已改由 common 提供) | [README](z2huo-framework-starter-sentinel/README.md) | ## 五、互斥关系与通用约定 ### 1、互斥关系 - `z2huo-framework-starter-redis` 与 `z2huo-framework-starter-redisson`:二选一,两者都注册 `redisTemplate` / `stringRedisTemplate` / `redisJsonMapper`。 - `z2huo-framework-starter-cache` 依赖 redisson starter,引入它之后不要再引 redis starter。 - `z2huo-framework-starter-druid` 与 `z2huo-framework-starter-hikaricp`:二选一。两者的配置模板**同名**(都是根目录 `application-z2huo-datasource.yaml`),互斥靠约定而非机制保证;同时引入时命中哪份由 classpath 顺序决定,且两个 starter 都写 `spring.datasource.*` 单一数据源模型,`type` 与池参数也会矛盾。 - `z2huo-framework-starter-mybatis-plus` 与连接池 starter 是**配合关系而非互斥**:它只负责 ORM 层,不绑定连接池实现,运行时通过官方 `MybatisPlusAutoConfiguration` 消费容器中的 `DataSource`。使用它必须再引 druid 或 hikaricp 之一来提供 `spring.datasource.*`,否则 `DataSourceAutoConfiguration` 因无 URL 启动失败。 - `z2huo-framework-starter-mybatis-plus-join` 是 `z2huo-framework-starter-mybatis-plus` 的**超集**(已传递依赖它),二者不要同时显式引入;需连表时只引 `-join`,单表场景只引核心 MP starter(因为 mybatis-plus-join 一旦上 classpath 就全局注册 `@Primary ISqlInjector` 与 `MPJInterceptor`,无法按 Mapper 粒度关闭)。 - `z2huo-framework-starter-nacos-config` 与 `z2huo-framework-starter-nacos-discovery`:同一个能力域拆成的两半,不是互斥关系,按需单引或两个都引。拆分前它们在一个 starter 里,只想要配置中心的应用必须靠环境变量把 `spring.cloud.nacos.discovery.enabled` 置 false 才不会被注册成实例(该 key 已在模板里落值,应用主文档改不动);拆分后这个退出通道变成「不引那个依赖」。 - `z2huo-framework-starter-nacos-discovery` 与 `z2huo-framework-starter-dubbo` 是**并行而非重复**:两者都可能连到同一个 Nacos 集群,但走的是两套互不相干的适配——Dubbo 侧用 `dubbo-nacos-spring-boot-starter` 的 SPI 注册 Dubbo 服务实例(分组默认 DUBBO),Spring Cloud 侧用 `spring.cloud.nacos.discovery.*` 注册应用实例(分组默认 DEFAULT_GROUP)。同时引入没有 Bean 冲突,但两边的 server-addr 与 namespace 得各自填一致。 - `z2huo-framework-starter-sentinel` 与 `z2huo-framework-starter-nacos-config` 看着重叠,实则无关:Sentinel 的 Nacos 规则源走原生 `nacos-client` 自建 `ConfigService`,不经过配置中心那套 config data 抽象。引 sentinel 不会得到配置中心能力,引 nacos-config 也不会替 Sentinel 提供规则源。 - `z2huo-framework-starter-sentinel` 与 `z2huo-framework-starter-dubbo` 是**配合关系**:Dubbo 侧的桥接 Filter(optional)留在 dubbo starter,规则源模板与拦截应答统一在 sentinel starter,两份模板之间不再有 `${dubbo.registry.parameters.namespace}` 这类占位符耦合。 - 不要同时引入旧坐标 `cn.z2huo:spring-boot-demo-starter*`。它已随孵化完成从仓库移除,但本地仓库可能仍残留当时 `install` 的 `0.0.1` 产物;两者的 `logback-spring.xml` 在 classpath 根路径同名,命中哪份取决于 jar 顺序。 ### 2、通用约定 1. 所有版本统一由 `z2huo-framework-dependencies` 管理,使用方的 `` 不写 ``。 2. jar 内的 yaml 不会被 Spring Boot 自动加载,必须 `spring.config.import=optional:classpath:application-z2huo-...` 显式导入(例外情形见第二节:激活同名 profile 会绕过导入直接生效)。这是配置型 starter 最容易漏的一步,也是各模块 README 存在的核心原因。 3. **优先级是「文档级」而不是「文件级」**(已实测,与直觉相反):被导入文档只高于**声明该导入的那个文档**。模板里落了值的 key,写在应用与 `spring.config.import` 同一个文档里覆盖不掉;能压过模板的通道是环境变量、JVM 参数、命令行、`spring.config.additional-location` 指向的文件,以及**应用自己文件里用 `---` 分出的后续文档**(带不带 `spring.config.activate.on-profile` 都行)。因此模板**可以**给参数落默认值,覆盖通道始终留着;只有「既想给默认值、又要应用在同一个文档里改」这一种需求才要求模板不收这一行。注意独立的 `application-{profile}.yaml` 文件是个例外:它对环境变量一类属性有效,但对在 config data 阶段就绑定完毕的 `NacosConfigProperties` 无效(详见 `-nacos-config` 的 README)。 4. 模板自身可以用 `---` + `spring.config.activate.on-profile` 按环境分段:nacos 两份模板就是这么放地址与命名空间的(默认段落即 local,后续段落只写差异项,未命中的段落完全不贡献)。profile 可以来自环境变量,也可以来自应用主文档,两者同样生效。**不要**改用 `application-z2huo-xxx-{profile}.yaml` 这种变体文件做同一件事:Spring Boot 确实会自动追加加载它、优先级也更高,但它进环境的时机晚于配置中心侧的绑定,表现为「看着最高、实际没生效」(已实测)。 5. 还有一种介于「不落值」与「落字面默认值」之间的形态:模板里落的不是字面值而是**带默认值的占位符引用**(如 sentinel 模板的 `server-addr: ${spring.cloud.nacos.server-addr:nacos.dev.z2huo.cn:8848}`)。占位符在绑定期对整个 Environment 求值,与导入顺序、与被引用 key 所在文档的优先级都无关,所以应用写该 key 依旧生效,同时保住了默认值(已由 `z2huo-framework-example-sentinel` 的契约测试验证)。代价是参数多一层间接,使用时须在 README 里写明。 6. starter 的验证示例统一放在 `z2huo-framework-examples` 聚合下,与被验证的 starter 同仓演进;示例的 parent 是 `z2huo-framework-parent`(聚合与继承是两条独立关系)。按中间件能力横评的示例留在业务仓库 `demos-*` 目录下,不随框架分发。 7. 除工具基线外,框架不把依赖全局注入给子模块,每个模块只声明自己源码实际用到的依赖。工具基线是故意开的口子:`z2huo-framework-common` 以 compile 携带 hutool-core、commons-lang3、commons-collections4,使使用方引任一 starter 即可直接 import 而无需写自己 pom(详见第六节第 6 条);能力型依赖(guava、hutool-crypto/http/json、commons-io/text)仍一律按需声明。 8. 出入参契约类(`ApiResult` / `PageData` / `PageCondition`)住在 `z2huo-framework-common`,不住 web starter:HTTP 与 Dubbo 共用同一个信封,纯 provider 不该为了拿信封而依赖 servlet 栈。 9. 全框架只有一个响应信封 `ApiResult`,不给分页或列表派生子类;分页载荷以 `ApiResult>` 的组合形态出现。失败也回 HTTP 200,业务结果只看响应体的 `success` 与 `code`。 10. 分页字段拼写全框架唯一,不得引入同义写法:请求 `currentPage` / `pageSize`,响应 `list` / `totalCount` / `currentPage` / `pageSize` / `totalPages`,数值类型一律 `long`。`pageNum` / `pageNo` / `pageIndex` / `records` 属禁用词。 11. 错误分三层表达,不得互相顶替:`code` 是 5 位定长的**类别码**(来源字母 + 类别族 2 位 + 族内条目 2 位,如 `A0400`),只回答「哪一类错、客户端该做什么」,取值集合由 `ErrorCategoryEnum` 封闭维护,业务不得自增;真正标识一个错误的是 `(domain, reason)` 二元组——`domain` 是产生错误的服务归属(由 `spring.application.name` 派生),`reason` 是 UPPER_SNAKE 的精确原因;`message` 面向开发者,`userTip` 才是给终端用户的文案。把 `code` 或 `message` 直接当用户提示语属违反约定。 12. 业务方新增错误码只需在自己的 `domain` 内保证 `reason` 唯一(只需 PR 追加登记,不需框架侧发号);新增 `code` 属对外契约扩张,必须走框架级变更。异常分支与错误码来源的一致性在构造期校验:`BusinessException` 只接 A 类码、`SystemException` 只接 B 类、`RemoteException` 只接 C 类;日志级别只由异常类决定,`ErrorCode` 不提供级别字段。 ## 六、契约要点 1. 两条接入通道的父 POM 选择各有取舍:框架根 POM 不继承任何 Boot POM,只聚合库模块并从 BOM 拿版本(继承应用侧 parent 会让 starter jar 有被 repackage 的风险);`z2huo-framework-parent` 则直接继承 `spring-boot-dependencies` 而非 `spring-boot-starter-parent`,以拿到插件版本同时剔无用配置。注意只有「继承」才带来 `pluginManagement`,`import` 不会。 2. `dependencyManagement` 只沿 parent 链传递,聚合关系不传递。因此框架根 POM 必须 `import` BOM,子模块才能省写版本;而 BOM 自身刻意不设 parent,保持对外完全自包含。 3. 根 POM 中有两个属性是 BOM 的**构建期镜像**(`spring-boot.version`、`mapstruct.version`),因为 `import` 不传递属性,而 `maven-compiler-plugin` 的 `annotationProcessorPaths` 必须有可用版本。升级时两处必须同步,见第八节检查点。`lombok.version` 是例外的第三个:BOM **不声明** lombok 坐标(直接声明会压住 `spring-boot-dependencies` 的管理值),所以根 POM 里那一个是全仓库唯一的 lombok 字面量,它只靠人工与 Boot 对齐。 4. CI 友好版本 `${revision}` 必须经 flatten 处理后再安装。`dependencyManagement` 中框架自身模块的版本一律写 `${revision}`,禁止写 `${project.version}`,后者不会被 flatten 解析,会让外部项目拿到字面量而解析失败。 5. 外部项目解析 starter 时需要完整 parent 链(模块 POM 中保留 `` 且依赖项不带版本号),因此框架所有层级的 POM 必须整体 `install`/`deploy`,不能只发 jar。 6. 工具基线:`z2huo-framework-common` 的 compile 工具依赖即「引 starter 即得」的对外承诺清单,当前为 hutool-core(日期/Bean 复制/ID/随机/线程/断言/IO 资源)、commons-lang3(字符串/对象/数组)、commons-collections4(集合/Map)。增项随时可做,换 provider 或删除属破坏性变更。基线只随 common 传递,因此依赖 common 的 starter(base、web、sentinel、dubbo、redis、redisson、mybatis-plus)能带到;纯聚合型 starter(nacos-config、nacos-discovery、cache、skywalking、druid、hikaricp、test、mybatis-plus-join)不带——这被认为可接受,因为真实应用必然引 base starter。 7. 工具库版本策略:`spring-boot-dependencies` 已管理的坐标(commons-lang3、commons-codec、commons-pool2、commons-dbcp2)一律**不得**在 BOM 重复声明,直接交给 Boot 供值——本 BOM 无 Boot parent,重复声明会把框架库模块压到旧版而业务应用拿新版,形成同坐标双版本(commons-lang3 曾因此出现 3.14.0 / 3.17.0 分裂)。Boot 未管理的坐标取可行范围内最新的稳定版;hutool 全族由 `hutool-bom` 一次性覆盖,禁止再逐个声明 `cn.hutool:*`。能力重叠(如 IO、转义)在 BOM 里两边齐列,由使用方自选 provider。 ## 七、构建与安装 前置环境为 JDK 21 与 Maven 3.9+。在仓库根目录执行: ```bash # 构建并安装到本地仓库 mvn clean install -DskipTests ``` 安装后产物位于 `~/.m2/repository/cn/z2huo/framework/`,业务仓库即可按上述任一方式消费。示例模块需要可用的 Redis 集群才能跑通测试,无中间件环境时用 `-DskipTests`。若改为私服分发,在本仓库根 POM 补 `` 后 `mvn deploy`。 ## 八、版本升级检查点 1. `z2huo-framework-dependencies/pom.xml` 的 `` 与全部依赖版本属性(版本权威在此)。 2. `z2huo-framework/pom.xml` 中的两个构建期镜像属性(`spring-boot.version`、`mapstruct.version`),另需单独核 `lombok.version`:它不在 BOM 里,必须等于所升 Boot 版本管理的 lombok 值(Boot 3.5.16 → 1.18.46),否则编译期处理器与运行期依赖会不同版。 3. `z2huo-framework-parent/pom.xml` 的 `` 与 `` 中的 `spring-boot-dependencies` 版本(该版本即 Boot 版本,本模块无需再写 `spring-boot.version`)。 4. 上游兼容性:`spring-cloud.version`、`spring-cloud-alibaba.version` 与 `spring-boot.version` 的对应关系需按官方版本兼容表核对。 5. 升级后逐 starter 跑 `mvn dependency:tree` 按 groupId 过一遍,确认没有坐标落到旧小版本:`import` 的 BOM 是「先声明者优先」,上游未收录的坐标(当前有 `sentinel-logging-slf4j`、`sentinel-apache-dubbo3-adapter`)会跟到次级 BOM 或无人管的默认值上。 ## 九、README 收录标准 **使用方能否只看 pom 就用对**。能,就不写;不能,就写。典型的「代码里看不出来」包括:必须显式导入的 jar 内配置文件、会被 classpath 隐式命中的 `logback-spring.xml`、两个 starter 争抢同一个 Bean 或同一组配置前缀、以及依赖扫描范围才生效的组件。 单篇控制在 100 行内,固定段落为定位、引入、启用、会得到哪些 Bean、约束与坑,末尾指向可运行示例;配置项较多时,在 Bean 与坑之间插入一节配置项。文档只维护契约,参数细节与代码由示例模块承载。指向业务仓库 `demos-*` 的引用写成行内代码而非相对链接,避免框架挪出后断链。