@PropertySource加载指定的属性文件(*.properties)到 Spring 的 Environment 中。可以配合 @Value 和@ConfigurationProperties 使用:@PropertySource 和 @Value组合使用,可以将自定义属性文件中的属性变量值注入到当前类的使用@Value注解的成员变量中;@PropertySource 和@ConfigurationProperties
组合使用,可以将属性文件与一个Java类绑定,将属性文件中的变量值注入到该Java类的成员变量中。
spring的@PropertySource注解只支持引入properties文件,引入yaml文件会报错,自定义PropertySourceFactory可以使之对yaml文件做支持
跟踪源码发现:
DefaultPropertySourceFactory#createPropertySource
中实现读取配置文件逻辑,如下:
public class DefaultPropertySourceFactory implements PropertySourceFactory {
@Override
public PropertySource<?> createPropertySource(@Nullable String name, EncodedResource resource) throws IOException {
return (name != null ? new ResourcePropertySource(name, resource) : new ResourcePropertySource(resource));
}
}
ResourcePrepertySource构造器:
public ResourcePropertySource(String name, EncodedResource resource) throws IOException {
super(name, PropertiesLoaderUtils.loadProperties(resource));
this.resourceName = getNameForResource(resource.getResource());
}
PropertiesLoaderUtils#loadProperties(resource):
public static Properties loadProperties(EncodedResource resource) throws IOException {
Properties props = new Properties();
fillProperties(props, resource);
return props;
}
能够确定使用Properties 读取的配置文件,所以只能支持.properties
类型的文件
为了对yaml文件做支持,继承DefaultPropertySourceFactory 重新实现读取方法,判断为yaml类型文件自定义读取逻辑,非yaml文件继续走之前的逻辑,如下:
package com.iscas.springboot.samples.property.resource;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.DefaultPropertySourceFactory;
import org.springframework.core.io.support.EncodedResource;
import java.io.IOException;
import java.util.Properties;
/**
* 兼容配置,使得@PropertyResource注解也能支持yaml
*
* @author zhuquanwen
* @vesion 1.0
* @date 2021/6/21 21:24
* @since jdk1.8
*/
public class MixPropertySourceFactory extends DefaultPropertySourceFactory {
@Override
public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
String sourceName = resource.getResource().getFilename();
if (sourceName != null && (sourceName.endsWith(".yml") || sourceName.endsWith(".yaml"))) {
//将yaml文件转为properties
return new PropertiesPropertySource(name, convert(resource));
} else {
return super.createPropertySource(name, resource);
}
}
private Properties convert(EncodedResource encodedResource) {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(encodedResource.getResource());
factory.afterPropertiesSet();
return factory.getObject();
}
}
测试:
定义一个yaml配置文件test-property-source.yml:
person:
zhangsan:
age: 18
使用:
package com.iscas.springboot.samples.property.resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 测试@PropertyResource
* @author zhuquanwen
* @vesion 1.0
* @date 2021/6/21 21:37
* @since jdk1.8
*/
@RestController
@RequestMapping("/test/property/resource")
@PropertySource(name = "test-property-source.yml", value = "classpath:test-property-source.yml", factory = MixPropertySourceFactory.class)
public class TestPropertyResource {
@Value("${person.zhangsan.age}")
private int age;
@GetMapping
public String testPropertyResource() {
System.out.println("张三年龄:" + age);
return "success";
}
}
访问这个接口,可以正常读取到张三年龄
2021-06-21 22:07:07.801 INFO 20404 --- [nio-5678-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2021-06-21 22:07:07.801 INFO 20404 --- [nio-5678-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2021-06-21 22:07:07.802 INFO 20404 --- [nio-5678-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms
张三年龄:18