Java中可通过实现PropertySourceFactory接口自定义加载YAML等非常规配置格式,配合@PropertySource注解使用,需引入Spring Core和Context模块,并在已初始化的应用上下文中运行。

Java 中通过 PropertySourceFactory 自定义加载非常规格式配置(如 YAML、JSON、TOML 或自定义文本结构),核心在于实现 Spring 的 PropertySourceFactory 接口,并配合 @PropertySource 注解使用。它适用于纯 Java 架构(即不依赖 Spring Boot 自动装配,但需引入 Spring Core 和 Context 模块)。
理解 PropertySourceFactory 的作用
PropertySourceFactory 是 Spring 提供的工厂接口,用于在 @PropertySource 加载资源时,决定如何将原始资源(如 InputStream)解析为 PropertySource。默认只支持 .properties 文件,要支持其他格式,必须提供自定义实现。
注意:该机制依赖 Spring 的 Environment 和 ConfigurableEnvironment,因此需确保应用上下文已初始化(如 AnnotationConfigApplicationContext),不是裸 JVM 环境。
编写自定义 PropertySourceFactory(以 YAML 为例)
假设你要加载 app.yaml,内容如下:
立即学习“Java免费学习笔记(深入)”;
server:port: 8080
database:
url: jdbc:h2:mem:test
你需要:
- 添加 YAML 解析依赖(如
snakeyaml) - 实现
PropertySourceFactory,将 YAML 转为扁平化的Map<String, Object> - 递归展开嵌套结构(如
server.port→"server.port" = "8080")
示例工厂类:
public class YamlPropertySourceFactory implements PropertySourceFactory {@Override
public PropertySource<?> createPropertySource(String name, EncodedResource resource)
throws IOException {
Yaml yaml = new Yaml();
Map<?, ?> yamlMap = yaml.load(resource.getInputStream());
Map<String, Object> flatMap = new LinkedHashMap<>();
flatten("", yamlMap, flatMap);
return new MapPropertySource(name != null ? name : resource.getResource().getFilename(), flatMap);
}
private void flatten(String prefix, Object value, Map<String, Object> result) {
if (value instanceof Map) {
((Map<?, ?>) value).forEach((k, v) -> {
String key = prefix.isEmpty() ? k.toString() : prefix + "." + k;
flatten(key, v, result);
});
} else {
result.put(prefix, value);
}
}
}
在配置类中声明 @PropertySource 并指定 factory
创建一个 @Configuration 类,用 @PropertySource 引入 YAML 文件,并通过 factory 属性指定你的工厂:
@PropertySource(value = "classpath:app.yaml", factory = YamlPropertySourceFactory.class)
public class AppConfig {
// 可配合 @Value 或 Environment 使用
然后启动上下文:
ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);Environment env = ctx.getEnvironment();
String port = env.getProperty("server.port"); // 返回 "8080"
支持 JSON/TOML 等其他格式的要点
原理一致,只需替换解析逻辑:
- JSON:用
com.fasterxml.jackson.databind.ObjectMapper读取为Map - TOML:引入
toml4j,调用Toml.parse()得到TomlTable,再递归展平 - 自定义格式(如 INI、KV 行式):按行解析,正则匹配
key=value,支持节头([section])则拼接前缀
关键点是最终都必须转换为扁平键值对(Map<String, Object>),因为 PropertySource 本质是键值集合,不保留嵌套结构。


















