文件服务 LinFile 统一提供配置文件、语言文件和数据库入口。本文介绍配置文件与语言文件共同使用的对象映射规则;数据库属于另一套数据模型。
ConfigService configService = lin.linFile().config();
LangService langService = lin.linFile().language();
DataService dataService = lin.linFile().database();
配置文件与语言文件都采用代码优先的结构:Java 类声明允许出现的字段、层级和默认值,YAML 或 JSON 文件提供运行时数据。
各项功能的使用方法见:
用于绑定配置或语言的 Java 类统称为「文件对象」。配置对象使用 @ConfigFile,语言对象通常使用 @LangPack。
@ConfigFile(name = "config")
public class MainConfig {
public String language = "zh_CN";
public Database database = new Database();
public static class Database {
public String host = "127.0.0.1";
public int port = 3306;
}
}
对应的 YAML 为:
language: zh_CN
database:
host: 127.0.0.1
port: 3306
文件中的嵌套结构与 Java 对象中的嵌套字段一一对应。内部映射时,Linlang 会把它们视为路径,例如 database.host,再完成默认值合并和字段填充。
文件对象及其嵌套对象应满足以下约束:
public 字段。public static class。文件对象可以包含供业务代码调用的普通方法,Linlang 不会自动调用它们。
首次绑定文件类时,Linlang 会构造一个根对象,先记录它的字段默认值,再将文件内容填入其中。绑定完成后,返回给开发者的就是这个对象,后文称为活动对象。
Linlang 会在绑定开始时记录该实例的独立默认值快照,用于判断和补齐缺失键;随后把磁盘数据填充到同一个实例。默认值快照由文件服务缓存并按只读数据使用,活动对象之后的字段修改不会反向改变默认值。reload() 与缺失补齐会复用这份快照,不会为了重新取得默认值再次构造同类对象。
同一服务重复绑定已经管理的类会复用其根对象。服务重建后再次绑定,则会创建新对象。配置中的动态 Map、List 条目也可能在加载时创建嵌套对象,不能把根对象的复用规则理解成所有构造方法永远只执行一次。
构造方法和字段初始化器仍然会执行,但应保持无副作用,不应执行以下操作:
@ConfigFile(name = "config")
public class MainConfig {
public String language = "zh_CN";
public Limits limits = new Limits();
public MainConfig() {
}
public static class Limits {
public int maxHomes = 3;
public Limits() {
}
}
}
显式声明空的无参构造方法不是必须的。
文件字段可以使用:
String、布尔值和数字类型。Instant 等由映射器明确支持的简单类型。List 与其他集合字段。Map<String, ?> 形式的映射字段。集合与 Map 的内容应由 YAML 或 JSON 能直接表达的元素、列表和映射组成。对于具有固定结构的数据,推荐优先使用嵌套类。
public List<String> worlds = new ArrayList<>();
public Map<String, Integer> limits = new LinkedHashMap<>();
请注意,如果您需要读取开放键集合,则应将对应字段声明为 Map,再通过 Map 访问。文件服务不会读取文件中额外添加的键生成 Java 对象。
flowchart TD
Bind["bind(FileClass)"] --> Metadata["读取文件注解与路径"]
Metadata --> Construct["无参构造一次活动对象"]
Construct --> Snapshot["记录默认值快照"]
Snapshot --> Read["读取 YAML 或 JSON"]
Read --> Merge["按字段路径合并缺失默认值"]
Merge --> Populate["填充同一个活动对象"]
Populate --> Emit{"允许写回?"}
Emit -->|是| Persist["生成或补齐磁盘文件"]
Emit -->|否| Return["返回活动对象"]
Persist --> Return
代码声明配置结构和默认值。默认值用于补齐缺失键,不表示文件中的错误值会被自动替换;配置输入错误的处理见配置校验 ⇱。
emit 参数控制本次绑定是否允许向磁盘文件写入:
MainConfig config = lin.linFile().config().bind(MainConfig.class, false);
MainLanguage lang = lin.linFile().language().bind(MainLanguage.class, false);
emit = false 表示可以读取并绑定,但不会创建、补齐或保存磁盘文件。也可以在类上声明 @NoEmit 禁止写回;两者任一禁止写回时,服务都不会生成文件。如果不显式传递 false,则 emit = true。
如果不希望生成配置文件,可以设置 emit = false。
同一个文件服务中的 reload() 会重新读取磁盘,并原地刷新已经绑定的活动对象。因此,普通重载后可以继续使用原引用。
lin.settings().apply() 原地应用语言等参数,不替换文件服务或绑定对象。显式重建或关闭后创建新 Facade 时,需要重新取得服务并绑定。
Linlang 和文件服务均使用 Unicode UTF-8 编码。若您在 Windows 下使用 Linlang,请注意文件编码问题。
讨论