1. 程式人生 > 實用技巧 >SpringBoot載入額外配置檔案的兩種方式

SpringBoot載入額外配置檔案的兩種方式

一、為什麼要學額外配置檔案

本節為大家介紹另外一種場景:有一些老的專案裡面的jar包並未主動的去與spring boot 融合,很多jar包都有自己的配置檔案。如果我們在spring boot專案中使用這些jar包就必須得使用它們的配置檔案,那就面臨一個問題:我們的spring boot專案預設只有一個全域性配置檔案:application.yml或application.properties。該如何載入額外的配置檔案?

如何解決這個問題,就是本節將為大家介紹的內容。

二、使用@PropertySource載入自定義yml或properties檔案

2.1.@PropertySource註解載入properties配置檔案

family.properties這種格式的配置檔案,在之前章節的程式碼基礎之上,使用如下的註解就可以將檔案中的配置屬性進行載入,非常簡單!

@PropertySource(value = {"classpath:family.properties"})
public class Family {

2.2.@PropertySource註解載入yaml配置檔案

但是這個註解只支援載入properties檔案,如何讓它載入yml格式的檔案呢?

spring 官方文件明確說明不支援使用@PropertySource載入YAML配置檔案,但是我們仍然有辦法,跟著我繼續。

  • 我們新建一個配置檔案family.yml,把上一節用到的YAML資料結構放裡面。用來模擬第三方jar包的額外配置檔案(非application配置檔案)。
# 新建一個配置檔案family.yml,
#  把上一節用到的YAML資料結構放裡面。用來模擬第三方jar包的額外配置檔案(非application配置檔案)。
# 如果主配置檔案中也有family屬性的話,就走主配置檔案當中的,不會走我們這個!

family:
  family-name: "happy family"
  father:
    name: zhoujinyuan
    beat: ${family.father.name:zhoujinyuan2}
    age: 24
  mother:
    alias:
      - aaa
      - bbb
  child:
    name: leijieqiong
    age: ${random.int}
    friends:
      - {hobby: football,sex:  male}
      - {hobby: basketball,sex: female}
  • 筆者通過閱讀程式碼瞭解到,DefaultPropertySourceFactory是進行配置檔案載入的工廠類。
  • 儘管其預設不支援讀取YAML格式外部配置檔案,但是我們可以通過繼承DefaultPropertySourceFactory ,然後對它的createPropertySource進行一下改造。就可以實現YAML的“額外”配置檔案載入。
package com.zhoujinyuan.springbootyml.util;

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 org.springframework.core.io.support.ResourcePropertySource;
import org.springframework.lang.Nullable;

import java.io.IOException;
import java.util.Properties;

/**
 * 實現YAML的“額外”配置檔案載入。
 * ·@PropertySource· 註解預設不支援載入yml配置檔案
 * 自定義一個類繼承DefaultPropertySourceFactory ,然後對它的createPropertySource進行一下改造。就可以實現YAML的“額外”配置檔案載入。
 */
public class MixPropertySourceFactory extends DefaultPropertySourceFactory {

    /**
     * 改造實現YAML的“額外”配置檔案載入。
     *
     * @param name      我們資原始檔的名字
     * @param resource  編碼資源的一個物件
     * @return
     * @throws IOException
     */
    public PropertySource<?> createPropertySource(@Nullable String name, EncodedResource resource) throws IOException {
        // return name != null ? new ResourcePropertySource(name, resource) : new ResourcePropertySource(resource);

        String sourceName = name != null ? name : resource.getResource().getFilename();

        //如果是yml格式配置檔案就先轉成properties檔案格式再走父類方法就好了。
        if (sourceName != null &&(sourceName.endsWith(".yml") || sourceName.endsWith(".yaml"))) {
            Properties propertiesFromYaml = loadYml(resource);
            //將YML配置轉成Properties之後,再用PropertiesPropertySource繫結
            return new PropertiesPropertySource(sourceName, propertiesFromYaml);
        } else {
            //如果是Properties檔案就預設走父類方法處理就好了。
            return super.createPropertySource(name, resource);
        }
    }

    //將YML格式的配置轉成Properties配置
    private Properties loadYml(EncodedResource resource) throws IOException{
        YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
        factory.setResources(resource.getResource());
        factory.afterPropertiesSet();
        return factory.getObject();
    }

}
  • 然後基於上一節的程式碼,在Family類的上面加上如下註解即可。通過factory屬性明確的指定使用我們自定義的MixPropertySourceFactory載入yml配置檔案。
@Data
@Component  // 必須加入容器內才能讀取配置檔案資訊
@ConfigurationProperties(prefix = "family") //接收yml配置的java實體類,表示配置的整體字首
@Validated  // 使主實體類以下的成員帶有校驗註解的都生效。(開啟校驗功能的)
@PropertySource(value = {"classpath:family.yml"}, factory = MixPropertySourceFactory.class) // 作用:載入配置檔案的,預設只支援properties格式的。屬性value:指明配置檔案位置。屬性factory:指定使用我們自定義的MixPropertySourceFactory載入yml配置檔案。
public class Family {

    //@Value("${family.family-name}")
    @NotEmpty
    private String familyName;   //成員變數名稱要和yml配置項key一一對應
    private Father father;
    private Mother mother;
    private Child child;
}

三、使用@ImportResource載入Spring的xml配置檔案

在沒有Spring註解的時代,spring的相關配置都是通過xml來完成的,如:XXX.xml。下面的XML配置的含義是:將com.zhoujinyuan.springbootyml.service.TestService例項化並注入到Spring上下文環境中。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--測試SpringBoot載入XML格式配置檔案-->
    <bean class="com.zhoujinyuan.springbootyml.service.TestService" id="testService"></bean>
    
</beans>
  • 新建一個空類,com.zhoujinyuan.springbootyml.service.TestService。
  • 測試用例,測試Spring上下文環境中是否有TestService這樣一個bean,有的話表示xml配置檔案已經生效,成功將testService例項化並注入到Spring上下文環境中:
@SpringBootTest
public class SpringbootYmlApplicationTests{

    @Autowired
    ConfigurableApplicationContext applicationContext;

    @Test
    public void test2(){
        //測試Spring上下文環境中是否有testBeanService這樣一個bean,有的話表示xml配置檔案生效
        Boolean bean = applicationContext.containsBean("testService");
        System.out.println(bean);
    }
}
  • 因為還沒使用@ImportResource載入XXX.xml,此時執行測試用例,輸出false表示XXX.xml配置檔案並未載入,所以沒有testService的存在
  • 在spring boot應用入口啟動類上加@ImportResource(locations = {"classpath:XXX.xml"}),該註解用來載入Spring XML配置檔案。
    此時再試一下測試用例,輸出:true。表示XXX.xml配置檔案被正確載入。
@SpringBootApplication
@ImportResource(locations = {"classpath:XXX.xml"})
public class SpringbootYmlApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootYmlApplication.class, args);
    }

}

輸出為true。