工作的時候,一般來說代碼都是分環境的,比如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創建的先後順序有關。沒有繼續調查,希望知道原因的朋友能幫忙解答~