让 @PropertySource 注解支持加载 yml 配置文件
by emanjusaka from https://www.emanjusaka.com/archives/annotation-@PropertySource-yml 彼岸花开可奈何
本文为原创文章,可能会更新知识点以及修正文中的一些错误,全文转载请保留原文地址,避免未即时修正的错误误导。
@PropertySource 默认只支持 properties 文件和 xml 文件,并不能加载 yml 或 yaml。我们可以通过自定义资源加载的工厂指定 yml 加载器去加载 yml 的配置文件。
@PropertySource
通过使用@PropertySource注解,可以在Spring应用程序中动态地加载属性文件,并将其中的属性注入到Bean中或其他需要使用属性值的地方。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(PropertySources.class)
public @interface PropertySource {
/**
* 指定属性源的名称。如果未指定,则根据属性文件的位置生成一个名称
*/
String name() default "";
/**
* 指定属性文件的位置。支持 classpath 和文件路径,但不支持使用通配符,每个位置必须对应一
* 个 .properties 文件。可以使用${...}占位符来引用已注册的属性源中的属性。
*/
String[] value();
/**
* 指定当找不到属性文件时是否忽略错误。默认为false,即如果找不到属性文件,将抛出异常
*/
boolean ignoreResourceNotFound() default false;
/**
* 指定属性文件的字符编码,默认为空。
*/
String encoding() default "";
/**
* 指定一个自定义的PropertySourceFactory类,用于创建属性源。默认使用标准资源文件的默认
* 工厂。
*/
Class<? extends PropertySourceFactory> factory() default PropertySourceFactory.class;
}
@PropertySource默认对properties文件和 xml 文件可以进行加载,但对于yml或者yaml不能支持
实现对于yml的支持
新建YamlAndPropertySourceFactory类继承 DefaultPropertySourceFactory,然后重写 createPropertySource():
package top.emanjusaka.properties.factory; import org.springframework.boot.env.YamlPropertySourceLoader; import org.springframework.core.env.PropertiesPropertySource; import org.springframework.core.env.PropertySource; import org.springframework.core.io.Resource; import org.springframework.core.io.support.DefaultPropertySourceFactory; import org.springframework.core.io.support.EncodedResource; import java.io.IOException; import java.util.List; import java.util.Properties; /** * @Author emanjusaka * @Date 2024/7/4 15:52 * @Version 1.0 */ public class YamlAndPropertySourceFactory extends DefaultPropertySourceFactory { @Override public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException { if (resource == null) { return super.createPropertySource(name, resource); } Resource res = resource.getResource(); if (!res.exists()) { return new PropertiesPropertySource(null, new Properties()); } else if (res.getFilename().endsWith(".yml") || res.getFilename().endsWith(".yaml")) { List<PropertySource<?>> sources = new YamlPropertySourceLoader().load(res.getFilename(), res); return sources.get(0); } return super.createPropertySource(name, resource); } }
使用时在@PropertySource注解中指定 factory 属性为上面自定义的工厂实现:
package top.emanjusaka.properties; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import top.emanjusaka.properties.factory.YamlAndPropertySourceFactory; /** * @Author emanjusaka * @Date 2024/7/4 15:49 * @Version 1.0 */ @Configuration @PropertySource(value = "classpath:config/config.yml", factory = YamlAndPropertySourceFactory.class) @ConfigurationProperties(prefix = "config") @Data public class ConfigProperties { private String url; private String username; }
config.yml 文件
在resources 目录下新建 config 文件夹,在里面新建 config.yml 文件
config: url: https://www.emanjusaka.top username: emanjusaka
测试验证
package top.emanjusaka;
import cn.hutool.extra.spring.SpringUtil;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import top.emanjusaka.properties.ConfigProperties;
@SpringBootApplication
public class Application {
private static ConfigProperties configProperties;
private static ConfigProperties getProperties() {
if (configProperties == null) {
configProperties = SpringUtil.getBean(ConfigProperties.class);
}
return configProperties;
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
System.out.println("url:" + getProperties().getUrl());
}
}
成功读取 yml 文件: