@PropertySource 分環境讀取配置

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章