java.lang.Object
io.github.theword.queqiao.core.config.Config

public final class Config extends Object
配置运行时值存储

职责边界:本类只负责把 Schema 中定义的 ConfigKey 变成一个可靠、类型安全、隔离良好的 Runtime Value Store。 不包含 YAML 解析、文件读写、同步、命令、热加载——那些分别属于 ConfigLoader、ConfigWriter、ConfigSynchronizer 与命令层。

 Config = Runtime Value Store   ← 本类
 ConfigLoader  = YAML → Runtime
 ConfigWriter  = Runtime → YAML
 ConfigRegistry= Schema
 

关键不变量:

  • 不暴露可变值引用:get 与 set 都经 ConfigCodec.copy(Object), 外部无法通过 config.get(listKey).add(...) 绕过校验直接改内部状态;
  • set 失败不污染旧值:先解析校验,全部通过后才写入;
  • load 原子替换:全部转换校验成功后才一次性替换状态,失败时保持原状态;
  • Key 归属校验:ConfigKey 以对象身份标识,使用其它 Registry 的 Key 会抛异常;
  • 不修改 ConfigKey:Schema 不可变,运行时状态可变,二者严格分离;
  • set 不落盘:持久化由 Phase 5 的 Writer 负责,避免批量修改产生多次 I/O。

并发:状态是不可变快照,持有在 AtomicReference 中。 get 无锁读取;set/reset/load 用 CAS 替换整份状态, 因此读操作不会看到"半加载"状态。

Since:
0.6.12
  • Constructor Details

    • Config

      public Config(ConfigRegistry registry)
      构造运行时值存储
      Parameters:
      registry - Schema 注册中心
  • Method Details

    • get

      public <T> T get(ConfigKey<T> key)
      读取生效值

      字段缺失时返回默认值(不是 null)。可变类型返回副本, 修改返回值不会影响内部状态。

      Type Parameters:
      T - 值类型
      Parameters:
      key - 配置项
      Returns:
      生效值副本
      Throws:
      ConfigValidationException - key 不属于本 Runtime 的 Registry
    • contains

      public boolean contains(ConfigKey<?> key)
      判断用户配置中是否显式存在该字段

      与 get(ConfigKey) 语义严格区分:缺失字段的 get 返回默认值, 但 contains 返回 false。

      Parameters:
      key - 配置项
      Returns:
      true 表示值来源于用户配置
    • isDefault

      public boolean isDefault(ConfigKey<?> key)
      判断当前值是否来源于默认值

      不是简单的 value.equals(defaultValue): 用户显式写了与默认值相同的值,仍然属于 USER,本方法返回 false。

      Parameters:
      key - 配置项
      Returns:
      true 表示值来源于默认值
    • set

      public <T> void set(ConfigKey<T> key, T value)
      设置运行时值

      流程:归属校验 → codec 解析(类型一致性)→ validator → copy → 写入。 任何一步失败都抛 ConfigValidationException,且旧值保持不变。

      不会自动落盘——持久化由调用方显式触发(未来命令层 set → save)。

      Type Parameters:
      T - 值类型
      Parameters:
      key - 配置项
      value - 新值
      Throws:
      ConfigValidationException - 类型不符或校验不通过
    • reset

      public <T> void reset(ConfigKey<T> key)
      恢复为默认值

      结果与"用户配置中不存在该字段"一致:get 返回默认值副本, contains 为 false,isDefault 为 true。 每次 reset 都经 codec 复制,因此多次 reset 得到的可变默认值互不影响。

      Type Parameters:
      T - 值类型
      Parameters:
      key - 配置项
    • load

      public void load(Map<String,Object> document)
      用一份已解析的配置文档原子替换运行时状态

      YAML 解析不在这里:由 ConfigFileReader 负责把文件解析成 Map<String, Object>(或 ConfigDocument)后调用本方法。

      原子性:先对全部已注册的 Key 完成"取值 → codec 解析 → validator", 全部成功后才一次性替换状态;任何一项失败都会抛异常并保持 load 之前的状态, 绝不会出现"一半新一半旧"。

      缺失即默认:文档中没有的字段不算错误,记为 ConfigValueSource.DEFAULT;只有"存在但类型错误 / 校验失败"才是配置错误。

      Parameters:
      document - 已解析的配置文档,可为 null(等价于空文档)
      Throws:
      ConfigValidationException - 存在类型错误或校验失败的字段
    • load

      public void load(ConfigDocument document)
      用一份已解析的配置文档原子替换运行时状态

      与 load(Map) 等价,但走的是统一的路径解析入口(ConfigDocument), 避免出现第二套路径遍历逻辑。

      Parameters:
      document - 已解析的配置文档,可为 null(等价于空文档)
      Throws:
      ConfigValidationException - 存在类型错误或校验失败的字段
    • size

      public int size()
      Returns:
      已注册配置项数量
    • snapshot

      public ConfigSnapshot snapshot()
      取当前状态的不可变快照

      供 Writer 等长操作使用:它们只处理快照,因此不会被并发的 set/load 影响, 也不会长时间持锁。

      Returns:
      运行时快照
    • describeEntries

      public List<String> describeEntries()
      供测试与调试使用的值快照描述
      Returns:
      形如 websocket_server.port=8080(USER) 的列表