Spring Boot 加载自定义 YML 配置文件:从原理到实战 Spring Boot 默认支持 application.yml 配置文件的加载,但在需要拆分配置(如将业务配置与系统配置分离)时,我们常需加载自定义 YML 文件(如 custom.yml)。与 properties 文件不同,自定义 YML 文件无法直接通过 @PropertySource 加载(默认不支持 YML 解析),需通过自定义 PropertySourceFactory 实现。从 “原理分析→实现步骤→实战示例→注意事项 ” 四个维度,详细讲解自定义 YML 配置的加载方法。
核心问题:为何自定义 YML 无法直接加载? Spring Boot 的 @PropertySource 注解默认仅支持 properties 格式 的配置文件(通过 DefaultPropertySourceFactory 解析),而 YML 文件采用缩进式语法,需要专用的解析器(如 YamlPropertiesFactoryBean)。
properties 文件 :键值对格式(key=value),可直接被 @PropertySource 解析;
YML 文件 :层级结构(key: value),需先转换为键值对格式(如 parent.child=value)才能被 Spring 识别。
因此,加载自定义 YML 文件的核心是:实现一个能将 YML 转换为键值对的 PropertySourceFactory 。
解决方案:自定义 YML 解析工厂(PropertySourceFactory) 通过自定义 PropertySourceFactory,利用 Spring 内置的 YamlPropertiesFactoryBean 解析 YML 文件,将其转换为 Properties 对象(键值对格式),供 @PropertySource 使用。
1. 实现 YmlPropertySourceFactory 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 import org.springframework.core.env.PropertiesPropertySource;import org.springframework.core.env.PropertySource;import org.springframework.core.io.support.EncodedResource;import org.springframework.core.io.support.PropertySourceFactory;import org.springframework.lang.Nullable;import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;import org.springframework.util.StringUtils;import java.io.IOException;import java.util.Properties;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class YmlPropertySourceFactory implements PropertySourceFactory { private static final Logger log = LoggerFactory.getLogger(YmlPropertySourceFactory.class); @Override public PropertySource<?> createPropertySource( @Nullable String name, EncodedResource resource ) throws IOException { Properties propertiesFromYaml = loadYamlIntoProperties(resource); if (propertiesFromYaml == null ) { return (name != null ) ? new PropertiesPropertySource (name, resource.getResource()) : new PropertiesPropertySource (resource.getResource().getFilename(), resource.getResource()); } String sourceName = name; if (!StringUtils.hasText(sourceName)) { sourceName = resource.getResource().getFilename(); } if (sourceName == null ) { log.error("无法获取配置文件名称: {}" , resource); throw new RuntimeException ("加载 YML 配置文件失败:" + resource); } return new PropertiesPropertySource (sourceName, propertiesFromYaml); } private Properties loadYamlIntoProperties (EncodedResource resource) { try { YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean (); factory.setResources(resource.getResource()); factory.afterPropertiesSet(); return factory.getObject(); } catch (IllegalStateException e) { log.error("解析 YML 文件失败: {}" , resource.getResource().getFilename(), e); return null ; } } }