正在载入

等待时间过长时请刷新页面

编写于

最近更新

配置文件

配置文件服务 ConfigService 可以将 Java 配置对象映射为插件数据目录中的 YAML 或 JSON 文件。配置结构、默认值和注释由代码声明,管理员可以在磁盘文件中修改实际值。

定义配置对象

配置对象必须使用 @ConfigFile,并满足 文件服务 ⇱ 中的对象约束。

import api.linlang.file.file.FileType;
import api.linlang.file.file.annotations.Comment;
import api.linlang.file.file.annotations.ConfigFile;
import api.linlang.file.file.annotations.Key;
import api.linlang.file.file.annotations.NamingStyle;

@ConfigFile(name = "config", format = FileType.YAML)
@NamingStyle(NamingStyle.Style.KEBAB)
@Comment("插件主配置文件")
public class MainConfig {

    @Comment("当前全局语言")
    public String language = "zh_CN";

    @Key("debug")
    public boolean debugMode = false;

    public Database database = new Database();

    public static class Database {
        public String host = "127.0.0.1";
        public int port = 3306;
    }
}

默认的 KEBAB 命名会把 debugMode 映射为 debug-mode,但字段上的 @Key("debug") 会覆盖自动命名。上例生成的 YAML 结构为:

# 插件主配置文件
# 当前全局语言
language: zh_CN
debug: false
database:
  host: 127.0.0.1
  port: 3306

文件位置

@ConfigFile 有三个参数:

  1. name:不含扩展名的文件名,默认为 config
  2. path:相对于插件数据目录的子目录,默认为空。
  3. formatFileType.YAMLFileType.JSON,默认为 YAML。

例如:

@ConfigFile(name = "database", path = "settings", format = FileType.JSON)
public class DatabaseConfig {
}

它对应:

plugins/<YourPlugin>/settings/database.json

绑定配置

通过 lin.linFile().config() 取得服务,再绑定配置类:

ConfigService configService = lin.linFile().config();
MainConfig config = configService.bind(MainConfig.class);

绑定时,服务会:

  1. 解析 @ConfigFile 声明的路径和格式。
  2. 构造配置对象并记录字段默认值。
  3. 读取已有文件,或以默认值建立新文档。
  4. 执行适用的版本迁移。
  5. 补齐缺失键,完成类型转换与校验,汇总可以定位的问题。
  6. 校验成功后提交更新,并在允许写回时生成或更新文件。

提交与失败处理的详细流程见配置校验 ⇱

返回对象可以直接读取和修改:

if (config.debugMode) {
    getLogger().info("Debug mode enabled");
}

缺失键与差异文件

当已有配置缺少代码中声明的字段时,Linlang 会在内存文档中使用默认值补齐。允许写回且配置校验成功时,生成同名的 -diff 文件标记缺失路径,并更新原配置。

例如 config.yml 缺少字段时,旁边会出现:

config-diff.yml

差异文件用于提示管理员本次增加了哪些配置项,不应作为插件读取的主配置文件。

修改与保存

修改活动对象的公开字段后,调用 saveAll() 保存所有已绑定配置:

config.debugMode = true;
config.database.host = "db.example.com";

configService.saveAll();

保存用于持久化代码对活动对象的修改。若管理员已经修改了磁盘文件,不要在读取前无条件调用 saveAll(),否则可能先用内存值覆盖这些编辑。

重新加载

磁盘配置被外部修改后,可以重新加载:

configService.reload();

reload() 会原地更新此前由该服务绑定的对象,不会返回新对象:

MainConfig config = configService.bind(MainConfig.class);
configService.reload();

String language = config.language;

reload() 以有效的磁盘内容更新活动对象,不会合并尚未保存的内存修改。应根据实际修改来源选择保存或重载。

同一配置类重复绑定会复用并刷新活动根对象,不会重复执行根对象构造方法。普通嵌套对象尽量原地更新;Map、List、数组和配置文本字段可以被替换,因此重载后应从活动对象重新获取它们。为 Map、List 中新建的配置对象仍需提供公开无参构造方法。

加载失败时保留该文件的旧活动值,其他文件仍会继续重载。失败结果、错误注释及保存保护统一见配置校验 ⇱

lin.settings().apply() 只原地应用运行参数,不会重读配置或替换配置服务。原有 configService 与根配置对象继续有效。

写回控制

只读取而不允许生成或保存文件时,可以在绑定时传入 false

MainConfig config = configService.bind(MainConfig.class, false);

也可以在配置类上使用 @NoEmit

@NoEmit
@ConfigFile(name = "external")
public class ExternalConfig {
}

两种方式都会禁止该绑定的磁盘写回,包括首次生成、缺失补齐和后续保存。读取和对象填充仍会执行。

字段注解

配置对象可使用以下注解:

注解作用
@ConfigFile声明文件名、子目录和格式
@NamingStyle设置类中字段的自动命名方式
@Key为单个字段指定文件键名
@Comment为 YAML 类或字段写入注释
@NoEmit禁止生成和写回文件
@ConfigVersion声明配置版本与版本键

@Comment 只影响 YAML 输出。JSON 格式不会保存注释。

配置版本

可以使用 @ConfigVersion 在文件中记录结构版本:

@ConfigFile(name = "config")
@ConfigVersion(2)
public class MainConfig {
    public String newName = "default";
}

默认版本键为 _linlang-version。读取旧版本配置时,运行时会按当前版本查找连续的 Migrator,先修改文档,再填充对象。如果迁移链缺失、重复或文件版本高于代码支持版本,绑定会失败,以避免在未知结构上继续运行。

迁移器应在绑定对应配置类之前注册:

configService.registerMigrator(new Migrator() {
    @Override
    public int from() {
        return 1;
    }

    @Override
    public int to() {
        return 2;
    }

    @Override
    public boolean supports(Class<?> configType) {
        return configType == MainConfig.class;
    }

    @Override
    public void migrate(MutableDocument doc) {
        Object value = doc.get("old-name");
        doc.set("new-name", value);
        doc.remove("old-name");
    }
});

MainConfig config = configService.bind(MainConfig.class);

迁移链中每一步的 from() 必须等于上一步结束后的版本,to() 必须向目标版本推进。例如可以注册 1 -> 22 -> 3,也可以用一个迁移器完成 1 -> 3。同一配置类型和起始版本只能存在一个适用迁移器。需要一次注册多个迁移器时,可以使用 registerMigrators(...)

讨论

请登录账号