简介

  • 定位:统一的“配置能力注册与治理”基础设施,提供类型安全的 Provider 契约、依赖/冲突建模、拓扑初始化与状态流分发,面向全应用各业务模块复用。
  • 核心目标:
    • 类型安全:以 IFeatureConfigProvider/FeatureState 为强约束,编译期可检查。
    • 一致性:依赖/冲突统一在注册层校验,初始化顺序经拓扑排序保证。
    • 可扩展:模块化注册,多仓库并行。
  • 落地路径:为模块定义 ConfigModule → 在仓库 XxxRepository 中注册 Provider → 调用 initializeAsync() → 消费者订阅所需状态流。

设计初衷与要解决的问题

  • 统一配置能力,减少重复实现:历史上各模块各自实现开关/选项,规则分散、风格不一,难以复用与治理。
  • 显式建模依赖/冲突:跨模块特性耦合与互斥关系长期隐式存在,容易产生不可预期的组合与状态震荡。
  • 可验证的初始化顺序:启动/懒加载阶段并发初始化易引发竞态与“未注册先读”,需要确定性顺序与校验壁垒。
  • 类型安全与可观察性:弱类型配置与随意写通道导致运行时错误与状态不同步,需要强契约与可订阅状态流。

架构总览(mermaid)

注册生命周期与时序

Provider 契约(最小必要)

  • IFeatureConfigProvider:
    • isFeatureEnabled():特性可用性(资源/渠道/策略)
    • getDependencies()/getConflictsWith():显式依赖与互斥关系
    • stateFlow: StateFlow<FeatureState>:特性当前状态
  • BaseFeatureConfigProvider<TState : FeatureState>:
    • initDefaultValue():默认值恢复/迁移
    • onConfigStateUpdated(newState):状态变更后的副作用(持久化/系统调用)
    • updateConfigState { ... }:安全更新状态的唯一入口
示例(简化):

接入清单(Onboarding Checklist)

  1. 定义 ConfigModule:模块标识、依赖模块、Provider 列表。
  1. 建立 XxxRepository:继承 BaseConfigRepository,在 initializeAsync() 时注册模块。
  1. 实现 Provider:选择合适基类;声明依赖/冲突;实现默认值恢复与副作用。
  1. 消费者订阅:按需订阅 stateFlow 或查询仓库接口。
  1. 配置可视化与校验:在集成/预发阶段生成依赖图与分析报告。

关键校验与初始化要点

  • 循环依赖检测:DFS + 递归栈,防止初始化死锁。
    • 必要性:若不提前检测,将在初始化/订阅阶段形成死锁或不可达状态,定位成本高。
  • 依赖完整性验证:保证所有声明依赖均已注册,缺失即终止。
    • 必要性:缺失依赖会使拓扑不可解并引发运行时崩溃/降级失效,需在注册期阻断。
  • 冲突检测:检测互斥 Provider 同时启用的冲突并按策略回退或报错。
    • 必要性:避免运行期出现互斥功能同时开启造成 UI/逻辑抖动与状态反复回滚。
  • 拓扑排序:Kahn 算法确定初始化顺序,先依赖后依赖者。
    • 必要性:为并发初始化提供确定性序,消除竞态与“未注册先读”。
  • 初始化策略:
    • BaseFeatureConfigProvider:featureEnableConfigCheck() 更新启用态。
    • SwitchFeatureConfigProvider:initDefaultValue() 恢复/设置默认值并同步。
    • 必要性:统一默认值恢复与启用校验的时序与入口,保证状态幂等与可重复。

最佳实践与扩展

  • 设计:职责单一、依赖合理、通过资源/BuildConfig 控制 enable。
  • 性能:避免 Provider init 中的重 IO/CPU;按需懒加载;合并状态时去抖与背压。
  • 错误处理:提供默认行为与重试路径,详尽日志;失败可回滚。
  • 测试:覆盖注册/依赖/冲突/失败场景的单元测试。
  • 添加新 Provider:继承基类 → 实现抽象方法 → 加入注册列表 → 定义依赖/冲突。

错误处理要点

  • 模块重复注册:记录 warn,忽略重复保留首次。
  • 模块缺失依赖:初始化超时或失败,抛出全局初始化异常。
  • Provider 循环依赖/缺失依赖:终止注册完成流程并输出问题清单。
  • Provider 冲突同时启用:按策略回退或报错并提示不可达状态。
  • Provider 初始化异常:标记 loadingState=FAILED,供上层兜底与重试。

API 速查(精选)

FAQ 精选

  • Q: 两个 Provider 互相声明冲突怎么办?
    • A: 注册阶段会报告;选择“主导 Provider”回退从属。
  • Q: UI 如何感知全局初始化失败?
    • A: 订阅 Repository.loadingState,FAILED 显示兜底 UI 并提供重试。
  • Q: 如何在 Application 级预热?
    • A: 可在 App.onCreate 预热关键模块,但注意冷启动成本,推荐按需初始化。
  • Q: 如何做跨构建变体的特性屏蔽?
    • A: 在 Provider 中使用资源布尔与 BuildConfig 判定 enable,禁止 UI 写分支。
需求记录——白板克拉斯航海尺Note重构——数据驱动Setting模块