iT邦幫忙

2025 iThome 鐵人賽

DAY 9
1
Software Development

spring boot 3 學習筆記系列 第 9

Day09 - Spring Boot Properties 實戰與進階

  • 分享至 

  • xImage
  •  

Day08 內容裡,我們已經理解了 Properties 如同應用程式的「遙控器」,也認識了 Profiles 這個強大的多環境管理機制。現在,是時候學習如何將這些設定真正地「連接」到我們的 Java 程式碼中,讓應用程式根據我們的配置來運作。

今天將深入程式碼,掌握將配置注入到應用程式中的各種方法,並學習處理更複雜的配置場景與最佳實踐。

將屬性注入程式碼:三種核心方式

Spring Boot 提供了多種靈活的方式來讀取設定檔中的屬性。我們將介紹三種最主要的方法,從最簡單到功能最強大的逐一解析。

假設我們有以下的 application.properties 設定:

app.name=My Awesome App
app.version=1.0.0
app.description=這是一個很棒的應用程式!

方法一:@Value — 注入單一值

@Value 註解 (Annotation) 是最直接、最簡單的方式,適合用來讀取單一的屬性值。

使用方式:
您只需要在類別的屬性 (Field) 上方加上 @Value("${屬性名稱}") 即可。

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component // 標記為 Spring 的組件,讓 Spring 容器管理它
public class AppInfo {

    @Value("${app.name}")
    private String appName;

    @Value("${app.version}")
    private String appVersion;

    // 您也可以在這裡使用預設值
    @Value("${app.author:Default Author}")
    private String appAuthor;

    public void printAppInfo() {
        System.out.println("應用程式名稱: " + appName);
        System.out.println("應用程式版本: " + appVersion);
        System.out.println("應用程式作者: " + appAuthor); // 如果設定檔沒有 app.author,會顯示 "Default Author"
    }
}
  • ✅ 優點:語法簡單直觀,適合注入少量、分散的屬性。
  • ❌ 缺點:當屬性數量一多,程式碼會充滿大量的 @Value 註解 (Annotation),顯得雜亂且不易管理。

方法二:Environment 抽象 — 動態存取

Spring 的 Environment 是一個介面 (Interface),它代表了應用程式執行時的環境。您可以透過它以程式化的方式,動態地取得任何屬性值。

使用方式:
透過依賴注入 (Dependency Injection) 取得 Environment 物件,然後呼叫 getProperty() 方法。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;

@Service
public class MyDynamicService {

    @Autowired
    private Environment env;

    public String getAppName() {
        // 直接透過 key 來取得屬性值
        return env.getProperty("app.name");
    }

    public String getAppDescription() {
        // 也可以提供一個預設值
        return env.getProperty("app.description", "這是一個預設的描述。");
    }
}
  • ✅ 優點:非常靈活,可以在程式邏輯中動態決定要讀取哪個屬性。
  • ❌ 缺點:缺乏類型安全 (Type-safe),因為 getProperty() 回傳的都是字串 (String),您需要手動轉型,且如果屬性名稱拼錯,編譯器不會報錯,只會在執行時回傳 null

方法三:@ConfigurationProperties — 類型安全的結構化綁定 (👍 強烈推薦)

這是 Spring Boot 最推薦的方式。@ConfigurationProperties 可以將一組相關的屬性,直接「綁定」到一個 Java 物件 (POJO) 上,實現類型安全且結構化的配置管理。

使用步驟:

步驟 1:建立一個設定類別 (Configuration Class)

這個類別的屬性 (Field) 名稱必須和設定檔中的 key 對應。

import org.springframework.boot.context.properties.ConfigurationProperties;

// 將所有以 "app" 為前綴的屬性綁定到這個類別上
@ConfigurationProperties(prefix = "app")
public class AppConfig {

    private String name;
    private String version;
    private String description;

    // 必須提供對應的 Getter 和 Setter 方法!
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    public String getVersion() { return version; }
    public void setVersion(String version) { this.version = version; }

    public String getDescription() { return description; }
    public void setDescription(String description) { this.description = description; }
}

注意:Spring Boot 會自動進行駝峰式 (camelCase) 和 Kebab-case 的轉換。例如,設定檔中的 app.welcome-message 會自動對應到 Java 類別中的 welcomeMessage 屬性 (Field)。

步驟 2:啟用這個設定類別

要讓 Spring Boot 知道這個類別的存在,您有兩種方式:

  • 方式一 (推薦):在設定類別上加上 @Component 註解 (Annotation),讓它成為一個 Spring Bean。
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component // 讓 Spring 掃描並註冊這個 Bean
@ConfigurationProperties(prefix = "app")
public class AppConfig { /* ... 省略 ... */ }
  • 方式二:在主啟動類別上,使用 @EnableConfigurationProperties 來明確指定要啟用的設定類別。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;

@SpringBootApplication
@EnableConfigurationProperties(AppConfig.class) // 明確啟用 AppConfig
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

步驟 3:在其他地方注入並使用

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class AppService {

    private final AppConfig appConfig;

    // 透過建構子注入,這是 Spring 推薦的最佳實踐
    @Autowired
    public AppService(AppConfig appConfig) {
        this.appConfig = appConfig;
    }

    public void displayAppConfig() {
        System.out.println("從 AppConfig 讀取到的名稱: " + appConfig.getName());
        System.out.println("從 AppConfig 讀取到的版本: " + appConfig.getVersion());
    }
}
  • 優點
    • 類型安全:如果設定檔中的值無法轉換成正確的類型 (例如把 abc 設給一個 Integer 屬性),應用程式啟動時會直接報錯。
    • 結構化:將相關的設定組織在一個類別中,程式碼更清晰、更易維護。
    • IDE 支援:現代的 IDE (如 IntelliJ IDEA) 對 @ConfigurationProperties 有很好的支援,可以提供自動完成和語法檢查。

處理複雜結構:列表 (List) 與物件

@ConfigurationProperties 的強大之處在於它能輕鬆處理複雜的資料結構。

處理列表 (List)

假設您想設定一個支援的伺服器列表。

application.yml (推薦的格式)

server-list:
  hosts:
    - "server1.example.com"
    - "server2.example.com"
    - "server3.example.com"

application.properties (語法較繁瑣)

server-list.hosts[0]=server1.example.com
server-list.hosts[1]=server2.example.com
server-list.hosts[2]=server3.example.com

對應的 Java 設定類別

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;

@Component
@ConfigurationProperties(prefix = "server-list")
public class ServerListConfig {

    private List<String> hosts;

    public List<String> getHosts() { return hosts; }
    public void setHosts(List<String> hosts) { this.hosts = hosts; }
}

Spring Boot 會自動將設定檔中的多個值,綁定到 List<String> 結構中。

精通多重設定檔 (Profiles) 的運用

現在,讓我們將 Profiles 的概念與實際程式碼結合起來。

場景:我們希望在開發環境 (dev) 使用內嵌的 H2 資料庫方便快速啟動,而在正式環境 (prod) 則連接到外部的 MySQL 資料庫。

步驟 1:建立多個設定檔

  • application.properties (基礎設定)
# 預設啟用 dev 環境
spring.profiles.active=dev
app.name=My App
  • application-dev.properties (開發環境專用)
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
  • application-prod.properties (正式環境專用)
spring.datasource.url=jdbc:mysql://prod-db.example.com:3306/maindb
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.username=prod_user
spring.datasource.password=ToughPassword!
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect

步驟 2:在程式碼中根據 Profile 載入不同的 Bean

我們可以使用 @Profile 註解 (Annotation) 來告訴 Spring,某個 Bean 只在特定的 Profile 被啟用時才需要被建立。

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

// 一個設定類別的容器
@Configuration
public class DataSourceConfig {

    @Profile("dev") // 只有在 dev profile 啟用時,這個 Bean 才被建立
    public void devDatabaseBean() {
        System.out.println("======================================");
        System.out.println("      DEV 環境已啟用,使用 H2 資料庫");
        System.out.println("======================================");
    }

    @Profile("prod") // 只有在 prod profile 啟用時,這個 Bean 才被建立
    public void prodDatabaseBean() {
        System.out.println("**************************************");
        System.out.println("      PROD 環境已啟用,連接 MySQL 資料庫");
        System.out.println("**************************************");
    }
}

步驟 3:啟用不同的 Profile

  • 預設啟動:直接執行應用程式,因為 application.properties 中設定了 spring.profiles.active=dev,您會在控制台看到 "DEV 環境已啟用" 的訊息。
  • 透過命令列啟用 prod 環境
java -jar myapp.jar --spring.profiles.active=prod

執行後,您會在控制台看到 "PROD 環境已啟用" 的訊息。命令列參數的優先級高於設定檔中的設定。

重要注意事項與最佳實踐

  • 屬性覆寫的完整優先順序:請記住這個順序,當您發現設定不如預期時,這會是除錯的關鍵。

    1. 命令列參數 (最高)
    2. 作業系統的環境變數
    3. Profile-specific 設定檔 (如 application-prod.properties)
    4. 基礎設定檔 (如 application.properties)
    5. 程式碼中的預設值 (最低)
  • 大小寫敏感性:設定檔中的 key (如 app.name) 是大小寫不敏感的 (但建議統一小寫),而 @Value 中的佔位符 (Placeholders) ${app.name} 則是大小寫敏感的。

  • 中文亂碼問題:請確保您所有的 .properties.yml 檔案都使用 UTF-8 編碼儲存,以避免中文顯示為亂碼。

  • 敏感資訊管理絕對不要將資料庫密碼、API 金鑰等敏感資訊直接寫在設定檔並提交到版本控制系統 (如 Git)。最佳實踐是透過環境變數或專門的密鑰管理服務 (如 HashiCorp Vault, AWS Secrets Manager) 在部署時注入。

相關資料來源


上一篇
Day08 - Spring Boot Properties 概念入門
下一篇
Day10 - Spring Boot 依賴注入入門
系列文
spring boot 3 學習筆記17
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言