工作的时候,一般来说代码都是分环境的,比如 dev,test,prd 什么的,在用到 @PropertySource 注解的时候,发现好像不能根据环境读取自定义的.properties 文件,比如我有个 systemProperties-dev.properties 文件,一开始只是 systemProperties-${spring.profiles.active}.properties 这样的方式勉强能用,但是后来当我的环境变量变成多环境的时候,也就是 spring.profiles.active = dev,test 这样的是,这个方法就不奏效了,(多傻啊,其实早就想到了,他会直接在“-”后面拼了一个“dev,test”)然后在网上看了看资料,参考了以下的一篇文章,然后参照了下源码,用了一个比较简单,但是很难看的方法实现了:P(感觉也是暂时解决问题。)。参照文章:Springboot 中 PropertySource 注解多环境支持以及原理
主要思想,重写 PropertySourceFactory,在 PropertySourceFactory 中,重新取得 resource,
SystemProperties.java
@Component
@PropertySource(name=”systemConfig”, value = {“classpath:/systemConfig-${spring.profiles.active}.properties”}, factory = SystemPropertySourceFactory.class)
public class SystemProperties {
// 自己的内容 ….
}
这里指定了 factory = SystemPropertySourceFactory.class, 接下来
SystemPropertySourceFactory.java
@Configuration
public class SystemPropertySourceFactory implements PropertySourceFactory {
@Override
public PropertySource<?> createPropertySource(String name, EncodedResource encodedResource) throws IOException {
FileSystemResourceLoader resourceLoader = new FileSystemResourceLoader();
// 取得当前活动的环境名称(因为直接获取 spring.profiles.active 失败,所以才把环境名称拼在文件名后面来拿)
// 其实感觉应该有可以直接取的方法比如从环境里取
String[] actives = encodedResource.getResource().getFilename().split(“\\.”)[0].replace(name + “-“, “”).split(“,”);
// 如果只有一个,就直接返回
if (actives.length <= 1) {
return (name != null ? new ResourcePropertySource(name, encodedResource) : new ResourcePropertySource(encodedResource));
}
// 如果是多个
List<URL> resourceUrls = new ArrayList<>();
// 遍历后把所有环境的 url 全部抓取到 list 中
Arrays.stream(actives).forEach(active -> {
// 在 resource 目录下读取配置文件
URL url = this.getClass().getResource(“/” + name.concat(“-” + active).concat(“.properties”));
if (url != null) {
resourceUrls.add(url);
}
});
if (resourceUrls != null && resourceUrls.size() > 0) {
List<InputStream> inputStreamList = new ArrayList<>();
// 取得所有资源的 inputStream
for (URL url : resourceUrls) {
Resource resource0 = resourceLoader.getResource(url.getPath());
InputStream in = resource0.getInputStream();
inputStreamList.add(in);
}
// 串行流,将多个文件流合并车一个流
SequenceInputStream inputStream = new SequenceInputStream(Collections.enumeration(inputStreamList));
// 转成 resource
InputStreamResource resource = new InputStreamResource(inputStream);
return (name != null ? new ResourcePropertySource(name, new EncodedResource(resource)) : new ResourcePropertySource(new EncodedResource(resource)));
} else {
return (name != null ? new ResourcePropertySource(name, encodedResource) : new ResourcePropertySource(encodedResource));
}
}
}
这样实现后,就能将多个环境的 Property 文件加载进去了。
然后是关于 spring.profiles.active 为什么要这么取,我试过 @value, 和用 Environment 对象,都取不到,可能跟 bean 创建的先后顺序有关。没有继续调查,希望知道原因的朋友能帮忙解答~