淺析SpringBoot載入配置的6種方式

京東雲技術團隊發表於2023-10-30

從配置檔案中獲取屬性應該是SpringBoot開發中最為常用的功能之一,但就是這麼常用的功能,仍然有很多開發者抓狂~今天帶大家簡單回顧一下這六種的使用方式:

說明
Environment物件 Environment 是 springboot 核心的環境配置介面,它提供了簡單的方法來訪問應用程式屬性,包括系統屬性、作業系統環境變數、命令列引數、和應用程式配置檔案中定義的屬性等等,使用 Environment 方式來獲取配置屬性值非常簡單,只要注入Environment類呼叫其方法**getProperty(屬性key)**即可
@Value @Value註解是Spring框架提供的用於注入配置屬性值的註解,它可用於類的成員變數、方法引數和建構函式引數上, 在應用程式啟動時,使用 @Value 註解的 Bean 會被例項化。所有使用了 @Value 註解的 Bean 會被加入到 PropertySourcesPlaceholderConfigurer 的後置處理器集合中。當後置處理器開始執行時,它會讀取 Bean 中所有 @Value 註解所標註的值,並透過反射將解析後的屬性值賦值給標有 @Value 註解的成員變數、方法引數和建構函式引數。重要!!! ⚠️注意 ①在使用 @Value 註解時需要確保注入的屬性值已經載入到 Spring 容器中,否則會導致注入失敗; ②建議引用變數的時候給定一個預設值,避免啟動報“缺失配置”的錯誤; ③透過依賴注入的方式獲取物件中屬性值,切記不要使用new的方式來建立物件獲取其屬性。
@ConfigurationProperties SpringBoot 提供的一種更加便捷來處理配置檔案中的屬性值的方式,可以透過自動繫結和型別轉換等機制,將指定字首的屬性集合自動繫結到一個Bean物件上。
@PropertySources @PropertySources 註解的實現原理相對簡單,應用程式啟動時掃描所有被該註解標註的類,獲取到註解中指定自定義配置檔案的路徑,將指定路徑下的配置檔案內容載入到 Environment 中,這樣可以透過 @Value 註解或 Environment.getProperty() 方法來獲取其中定義的屬性值了。預設只限讀取properties檔案內容,想載入yaml檔案內容,可以自定義factory介面卡,指定factory具體的使用
YamlPropertiesFactoryBean物件 只限讀取yaml檔案,透過 @Value 註解或 Environment.getProperty() 方法來配合著獲取其中定義的屬性值。
JAVA原生 透過java.util.Properties去載入配置檔案中的屬性,

一、Environment

注入Environment類呼叫其方法getProperty(屬性key)即可

@Slf4j
@SpringBootTest
public class EnvironmentTest {

    @Resource
    private Environment env;

    @Test
    public void var1Test() {
        String var1 = env.getProperty("env.var1");
        log.info("Environment獲取的配置內容:{}", var1);
    }
}

二、@Value 註解

只要在變數上加註解 @Value("${env.var1}")就可以了,@Value 註解會自動將配置檔案中的env.var1屬性值注入到var1欄位中。

@Slf4j
@SpringBootTest
public class EnvVariablesTest {

    @Value("${env.var1}")
    private String var1;
    
    @Test
    public void var1Test(){
        log.info("配置檔案屬性: {}",var1);
    }
}

三、@ConfigurationProperties 註解

在 application.yml 配置檔案中新增配置項:

env:
  var1: 變數值1
  var2: 變數值2

建立一個 MyConf 類用於承載所有字首為env的配置屬性。

@Data
@Configuration
@ConfigurationProperties(prefix = "env")
public class MyConf {

    private String var1;
    
    private String var2;
}

在需要使用var1、var2屬性值的地方,將 MyConf 物件注入到依賴物件中即可。

@Slf4j
@SpringBootTest
public class ConfTest {

    @Resource
    private MyConf myConf;

    @Test
    public void myConfTest() {
        log.info("@ConfigurationProperties註解獲取的配置內容:{}", JSON.toJSONString(myConf));
    }
}

四、@PropertySources 註解

在 src/main/resources/ 目錄下建立自定義配置檔案 important.properties,增加兩個屬性。

env.var1=變數值1
env.var2=變數值2

在需要使用自定義配置檔案的類上新增 @PropertySources 註解,註解 value屬性中指定自定義配置檔案的路徑,可以指定多個路徑,用逗號隔開。

@Data
@Configuration
@PropertySources({
        @PropertySource(value = "classpath:important.properties", encoding = "utf-8"),
        @PropertySource(value = "classpath:important.properties",encoding = "utf-8")
})
public class PropertySourcesConf {

    @Value("${env.var1}")
    private String var1;

    @Value("${env.var2}")
    private String var2;
}

五、YamlPropertiesFactoryBean 載入 YAML 檔案

@Configuration
public class MyYamlConfig {

    @Bean
    public static PropertySourcesPlaceholderConfigurer yamlConfigurer() {
        PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
        YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
        yaml.setResources(new ClassPathResource("test.yml"));
        configurer.setProperties(Objects.requireNonNull(yaml.getObject()));
        return configurer;
    }
}

可以透過 @Value 註解或 Environment.getProperty() 方法來獲取其中定義的屬性值。

@Slf4j
@SpringBootTest
public class YamlTest {

    @Value("${env.var3}")
    private String var3;

    @Test
    public void  myYamlTest() {
        log.info("Yaml獲取配置內容:{}", var3);
    }
}

六、JAVA原生讀取

@Slf4j
@SpringBootTest
public class CustomTest {

    @Test
    public void customTest() {
        Properties props = new Properties();
        try {
            InputStreamReader inputStreamReader = new InputStreamReader(
                    this.getClass().getClassLoader().getResourceAsStream("test.properties"),
                    StandardCharsets.UTF_8);
            props.load(inputStreamReader);
        } catch (IOException e1) {
            System.out.println(e1);
        }
        log.info("Properties Name:" + props.getProperty("env.appName"));
    }
}

作者:京東零售 馬宏偉

來源:京東雲開發者社群 轉載請註明來源

相關文章