@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