天天看點

SpringBoot配置加載,各配置檔案優先級對比

文章内容:

  • SpringBoot配置檔案的基本使用;
  • yaml配置檔案優先級問題講解;
  • yaml配置檔案目錄及比較說明;
  • 自定義配置屬性;
    • @ConfigurationProperties與@Value兩種注解對比;
    • idea自定義yaml配置提示
  • 加載外部配置;
    • 裝配配置檔案(properties,yaml);
    • 引入xml配置檔案。

1.SpringBoot配置檔案

SpringBoot使用一個以application命名的配置檔案作為預設的全局配置檔案。支援properties字尾結尾的配置檔案或者以yml/yaml字尾結尾的YAML的檔案配置。

以設定應用端口為例

properties檔案示例(application.properties):

server.port=80
           

YAML檔案示例(application.yml):

server:
  port: 80
           

yaml文法規範可以參照該篇文章:https://blog.csdn.net/it_faquir/article/details/79842885

兩者同時存在情況

假如各配置檔案都配置了不同的端口,那麼SpringBoot會使用哪一個端口呢?帶着疑問試驗一下執行個體

  1. 在resources目錄下建立兩個配置檔案,一個為application.yml配置檔案,設定端口為8010,另一個為application.properties配置檔案,設定端口為8020;
  2. 重新開機系統;
  3. 運作結果:
    SpringBoot配置加載,各配置檔案優先級對比
  4. 結論:可見在同一目錄下,properties配置優先級 > YAML配置優先級。//是以我們在jar包啟動時帶上properties寫法的配置可以覆寫配置

2.配置檔案目錄

SpringBoot配置檔案可以放置在多種路徑下,不同路徑下的配置優先級有所不同。

可放置目錄(優先級從高到低)

  1. file:./config/ (目前項目路徑config目錄下);
  2. file:./ (目前項目路徑下);
  3. classpath:/config/ (類路徑config目錄下);
  4. classpath:/ (類路徑config下).

優先級由高到底,高優先級的配置會覆寫低優先級的配置;

SpringBoot會從這四個位置全部加載配置檔案并互補配置;

我們可以從ConfigFileApplicationListener這類便可看出,其中DEFAULT_SEARCH_LOCATIONS屬性設定了加載的目錄:

private static final String DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/";
           

接着getSearchLocations方法中去逗号解析成Set,其中内部類Loader負責這一配置檔案的加載過程,包括加載profile指定環境的配置,以application+’-’+name格式的拼接加載。

多種目錄配置同時存在情況

接下來還是以端口配置為例

  1. 在resources/目錄下配置檔案設定端口為8888;
  2. 在resources/config目錄下配置檔案設定端口為9999;
  3. 在項目路徑下配置檔案設定端口為6666;
  4. 在項目路徑config目錄下配置檔案設定端口為7777;
    SpringBoot配置加載,各配置檔案優先級對比
    最終運作結果:
Tomcat started on port(s): 7777 (http) with context path '/beedo'
Started BeedoApplication in 4.544 seconds (JVM running for 5.335)
           

通過控制變量法得以論證

其優先級由高到底,高優先級的配置會覆寫低優先級的配置

3.自定義配置屬性

SpringBoot提供了許多的配置,但通常情況我們需要自定義自己的配置應用自己的系統中,如你需要配置一個預設的使用者名密碼做為系統的登入用。

首先建立一個實體類,作為配置注入用,并使用**@ConfigurationProperties注解進行批量注入, 也可以使用Spring底層注解@Value("${user.username}")**的方式一個一個注入達到同意的效果

@Component
@ConfigurationProperties(prefix = "user")
public class Login{
    private String username;
    private String password;
    ...
}
           

或者@Value寫法

@Component
public class Login{
    
    private String username;
    private String password;
    ...
}
           

配置yaml檔案

user:
    username: admin
    password: 123
           

或者properties檔案

login.username=admin
login.password=123
           

編寫一個junit測試用例,看看配置的值是否正常注入:

@RunWith(SpringRunner.class)
@SpringBootTest
public class DeployApplicationTests {
    @Autowired
    private Login login;
    @Test
    public void contextLoads() {
        System.out.println(login);
    }
}
           

從輸出結果上看,值已正常注入

Login{username=‘admin’, password=‘123’}

@ConfigurationProperties與@Value兩種注解對比

比較項 @ConfigurationProperties @Value
全量注入 支援
松散綁定(Relaxed binding) 支援
SpEL 支援
JSR303 支援 不支援

**松散綁定:**駝峰命名(userName)、橫幹拼接(user-name)、下劃線(user_name)之間可以互相識别綁定稱為做松散綁定

**JSR303:**通過@Email,@Nullable,@Digits 等等注解進行郵箱、判空、數字格式等等資料的校驗,更多相關内容請參考IBM的中文文檔:https://www.ibm.com/developerworks/cn/java/j-lo-jsr303/index.html

@ConfigurationProperties通常用于将配置全量注入某個類中;

@Value通常用于注入某一些特定配置值中;

自定義配置提示

在編寫配置時,你會發現自定義配置沒有提示,讓你在使用自定義配置時變的很麻煩,其實SpringBoot早已為我們準備好了提示的需要,隻需要用引入相關依賴即可有提示。

在沒有加入依賴時idea會有如下提示:

SpringBoot配置加載,各配置檔案優先級對比

添加依賴,該idea提示便消失,編寫自定義配置時也有相應提示:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>
           

需要運作一下

4.指定配置檔案

通常情況下我們将配置配置在application開頭的主配置檔案中,這樣随着項目的增大配置項的增多會使檔案變得非常臃腫,其實SpringBoot早已考慮到了該問題,SpringBoot提供了**@PropertySource和@ImportResource**兩個注解用于加載外部配置檔案使用。

  • @PropertySource通常用于屬性加載配置檔案,注意@PropertySource注解不支援加載yaml檔案,支援properties檔案。
  • @ImportResource通常用于加載Spring的xml配置檔案

@PropertySource使用

裝配properties配置檔案

在sources/config下建立一個yaml檔案命名為user.properties内容與上方user的配置一樣

SpringBoot配置加載,各配置檔案優先級對比

Login類可如下寫法

@PropertySource(value = {"classpath:config/user.properties"})
@Component
@ConfigurationProperties(prefix = "user")
public class Login{
    private String username;
    private String password;
    ...
}
           

運作一下,同樣能達到加載配置效果

同時加載多個配置問題

細心的你,會發現@PropertySource注解中屬性value為一個數組,如果同時加載多個配置檔案,并且不同配置檔案中對同一個屬性設定了不同的值,那麼Spring會識别哪一個呢?

帶着疑問,我們可以通過控制變量法進行測試,具體過程再在贅述。

@PropertySource(value = {"classpath:config/user1.properties","classpath:config/user2.properties"})
           

結論:Spring加載順序為從左到右順序加載,後加載的會覆寫先加載的屬性值。

裝配yaml配置檔案

如果你有強迫症,一定想加載yaml配置檔案,那麼可以通過PropertySourcesPlaceholderConfigurer類來加載yaml檔案,将原來的user.properties改成user.yaml,Bean配置類中加入如下代碼,Login配置類和一開始的方式一緻。

@Bean
public static PropertySourcesPlaceholderConfigurer loadProperties() {
    PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
    YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
    //yaml.setResources(new FileSystemResource("classpath:config/user.yml"));//File路徑引入
    yaml.setResources(new ClassPathResource("config/user.yml"));//class路徑引入
    configurer.setProperties(yaml.getObject());
    return configurer;
}
           

運作一下,仍然可以能達到加載配置效果的

@ImportResource使用

SpringBoot提出零xml的配置,是以SpringBoot預設情況下時不會識别項目中Spring的xml配置檔案。為了能夠加載xml的配置檔案,SpringBoot提供了@ImportResource注解該注解可以加載Spring的xml配置檔案,通常加于啟動類上。

@ImportResource(value = {"classpath:/beans.xml"})
@SpringBootApplication(scanBasePackages = {"team.seagull.client"})
public class DeployApplication {
    public static void main(String[] args) {
        SpringApplication.run(DeployApplication.class, args);
    }
}
           

其他問題

idea使用*.properties檔案出現中文亂碼問題?

idea對*.properties預設編碼為GBK,通常我們項目為UTF-8編碼,這樣程式在讀取時就會出現亂碼問題;

解決方法:idea 中 打開如下選項File->Sttings->Editor->FileEncodings

SpringBoot配置加載,各配置檔案優先級對比

将GBK修改為UTF-8并勾選

Transparent native-to ascill conversion(在運作的時候轉換成ascii碼)

繼續閱讀