Spring Boot自定义yaml文件中如何使用环境变量?
解决方案
核心原因是默认的YAML解析工具仅会将文件内容解析为原生字符串,不会自动识别并替换${}格式的占位符,你可以根据自己的技术栈选择对应方案:
方案1:Spring Boot 场景(推荐)
这是Spring生态下的标准实现,无需自己写解析逻辑:
- 先实现自定义YAML配置源工厂,解决Spring默认
@PropertySource不支持加载YAML文件的问题:
import org.springframework.boot.env.YamlPropertySourceLoader; import org.springframework.core.env.PropertySource; import org.springframework.core.io.support.EncodedResource; import org.springframework.core.io.support.PropertySourceFactory; import java.io.IOException; import java.util.List; public class YamlPropertySourceFactory implements PropertySourceFactory { @Override public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException { List<PropertySource<?>> propertySources = new YamlPropertySourceLoader() .load(resource.getResource().getFilename(), resource.getResource()); return propertySources.get(0); } }
- 绑定配置类,自动完成占位符解析和属性注入:
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; @Configuration @PropertySource(value = "classpath:cache-config.yaml", factory = YamlPropertySourceFactory.class) @ConfigurationProperties(prefix = "cache-name-1") // 如果用Lombok直接加@Data注解即可,无需手写get/set public class CacheConfig { private Long ttl; private Long maxIdleTime; public Long getTtl() { return ttl; } public void setTtl(Long ttl) { this.ttl = ttl; } public Long getMaxIdleTime() { return maxIdleTime; } public void setMaxIdleTime(Long maxIdleTime) { this.maxIdleTime = maxIdleTime; } }
Spring会自动从环境变量、系统属性、application配置等多来源匹配占位符的key,找不到对应值就自动使用冒号后的默认值。
方案2:手动解析YAML场景
如果你是自己用SnakeYaml等工具读取YAML文件,可以自己实现占位符解析逻辑:
- 基于Spring环境的话直接注入
StringValueResolver完成解析:
// 注入Spring提供的字符串解析器 @Autowired private StringValueResolver stringValueResolver; // 读取到YAML的字符串值后调用解析方法即可 String resolvedValue = stringValueResolver.resolveStringValue(rawValue);
- 完全脱离Spring的话可以自己实现正则匹配解析:
import java.util.regex.Matcher; import java.util.regex.Pattern; public class PlaceholderResolver { private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("\\$\\{([^:]+)(?::([^}]+))?}"); public static String resolve(String rawValue) { Matcher matcher = PLACEHOLDER_PATTERN.matcher(rawValue); StringBuffer sb = new StringBuffer(); while (matcher.find()) { String key = matcher.group(1); String defaultValue = matcher.group(2); // 优先读环境变量 String value = System.getenv(key); // 找不到则读系统属性 if (value == null) { value = System.getProperty(key); } // 仍找不到则使用默认值 if (value == null) { value = defaultValue; } matcher.appendReplacement(sb, value); } matcher.appendTail(sb); return sb.toString(); } }
读取YAML后遍历所有值调用上述解析方法替换即可。
内容的提问来源于stack exchange,提问作者Mesut Can
相关产品推荐
相关产品推荐

