Spring Boot 讀取設定檔詳解(預設值、設定檔類別、靜態成員賦值)


有非常多的資訊都會寫在設定檔,主要就是那些可能會頻繁變更的資訊,例如資料庫連接的帳號密碼等

Spring Boot 的設定檔有兩種,分別是 application.properties 和 application.yml
這兩種的差別就差在撰寫方式的不同,直接來看看這兩個檔案:

application.yml:
    
spring:
  datasource:
    url : jdbc:oracle:thin:@localhost:1521:XE
    driverClassName : oracle.jdbc.driver.OracleDriver
    username : RUYUT
    password : abcd1234
    

application.properties:
    
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:XE
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.datasource.username=RUYUT
spring.datasource.password=abcd1234
    

該檔案存放的路徑如下:
註:雖然這兩個檔案可以同時存在,但非常不建議。預設會先讀取 yml,再讀取 properties,所以很可能發生找半天才發現原來問題出在設定檔被蓋掉的情況
    
RuyutExample/
`-- src/
    `-- main
        `-- resources/
            |-- application.yml
            `-- application.properties
    

讀取設定值

我們直接建立一個 ConfigurationController ,本次就直接在這個控制器中做示範

範例設定檔內容如下:
    
ruyut.blog.url=https://www.ruyut.com/
    

讀取設定檔中的 "ruyut.blog.url" 設定值至 applicationName 變數:
    
@Value("${ruyut.blog.url}")
private String ruyutBlogUrl;
    

完整呼叫範例:
執行程式後使用瀏覽器開啟 http://localhost:8080/configuration 即可看到設定值有成功被讀取
    
package app.ruyut.ruyutexample.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class ConfigurationController {

    @Value("${ruyut.blog.url}")
    private String ruyutBlogUrl;

    @GetMapping("configuration")
    public ResponseEntity<String> configuration() {
        return ResponseEntity.ok(ruyutBlogUrl);
    }

}
    

設定檔預設值

如果這時候把剛剛的設定值刪掉,執行程式時會拋出下列錯誤:
    
Error creating bean with name 'configurationController': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'ruyut.blog.url' in value "${ruyut.blog.url}"
    

原因是因為設定值不存在,所以在自動注入的時候發生錯誤,要避免這個問題的方式就是加上預設值
只要在後面加上冒號(:),冒號後面的就是預設值
    
    @Value("${ruyut.blog.url:https://ruyut.app}")
    private String ruyutBlogUrl;
    

此時再執行程式已經不會出現錯誤了

設定檔類別

假設我們有很多設定值,我們應該要新增一個組態設定的類別來存放特定類別的所有設定值
設定檔類別範例:
    
package app.ruyut.ruyutexample.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Value("${ruyut.blog.url:https://ruyut.app}")
    public String ruyutBlogUrl;

}
    

讀取範例:
    
package app.ruyut.ruyutexample.controller;

import app.ruyut.ruyutexample.config.AppConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class ConfigurationController {

    @Autowired
    private AppConfig appConfig;

    @GetMapping("configuration")
    public ResponseEntity<String> configuration() {
        return ResponseEntity.ok(appConfig.ruyutBlogUrl);
    }

}
    

解決自動注入到靜態成員 NULL

不知道你有沒有發現,如果在 @Value 下面的那個變數是靜態成員(static),則那個變數,無法被正常賦值(注入),該變數都會是 null
    
    @Value("${ruyut.blog.url:https://ruyut.app}")
    public static String ruyutBlogUrl;
    

嗯,這就是 Spring Boot 法律規範,無法處理...

不過,可以用個小方法繞過
    
    @Value("${ruyut.blog.url:https://ruyut.app}")
    private void setRuyutBlogUrl(String ruyutBlogUrl) {
        this.ruyutBlogUrl = ruyutBlogUrl;
    }
    public static String ruyutBlogUrl;
    

完美,這就是程式的魅力所在!

留言