知識庫 / Spring / Spring Boot RSS 訂閱

Spring 和 Spring Boot 中的屬性配置

Spring Boot
HongKong
10
03:02 PM · Dec 06 ,2025

1. 概述

本教程將演示如何通過 Java 配置和 @PropertySource 來在 Spring 中設置和使用屬性。

我們還將瞭解屬性在 Spring Boot 中的工作原理。

2. 通過註解註冊屬性文件

Spring 3.1 還引入了 @PropertySource 註解">@PropertySource 註解作為一種便捷的機制,用於向環境添加屬性源。

我們可以將此註解與 @Configuration 註解">@Configuration 註解結合使用:

@Configuration
@PropertySource("classpath:foo.properties")
public class PropertiesWithJavaConfig {
    //...
}

使用佔位符註冊新的屬性文件也是一種非常有效的方法,它允許我們在運行時動態地選擇正確的屬性文件:

@PropertySource({ 
  "classpath:persistence-${envTarget:mysql}.properties"
})
...

2.1. 定義多個屬性位置

<em>@PropertySource</em> 註解是可重複使用的,遵循 Java 8 的約定(詳見 Java 8 約定)。因此,如果使用 Java 8 或更高版本,我們可以使用此註解來定義多個屬性位置:

@PropertySource("classpath:foo.properties")
@PropertySource("classpath:bar.properties")
public class PropertiesWithJavaConfig {
    //...
}

當然,我們也可以使用 @PropertySources 註解並指定一個 @PropertySource 的數組。這在任何支持的Java版本中都有效,不僅僅是Java 8或更高版本:

@PropertySources({
    @PropertySource("classpath:foo.properties"),
    @PropertySource("classpath:bar.properties")
})
public class PropertiesWithJavaConfig {
    //...
}

在任何情況下,如果屬性名稱發生衝突,則最後讀取的源數據將優先使用。

3. 使用/注入屬性

使用@Value註解注入屬性非常簡單:

@Value( "${jdbc.url}" )
private String jdbcUrl;

我們還可以為該屬性指定一個默認值:

@Value( "${jdbc.url:aDefaultUrl}" )
private String jdbcUrl;

新添加的 PropertySourcesPlaceholderConfigurer 在 Spring 3.1 中 可以解析 bean 定義屬性值和 @Value 註解中的 ${…} 佔位符。

最後,我們可以使用 Environment API 獲取屬性值:

@Autowired
private Environment env;
...
dataSource.setUrl(env.getProperty("jdbc.url"));

4. 使用 Spring Boot 的屬性

在深入探討 Spring Boot 中更高級的配置選項之前,我們先花一些時間來了解一下新的屬性支持。

總的來説,這種支持與標準 Spring 相比,配置量更少,這當然是 Boot 的主要目標之一。

4.1. application.properties: 默認屬性文件

Boot 採用約定優於配置的策略來處理屬性文件。這意味着我們可以簡單地將 application.properties 文件放在我們的 src/main/resources 目錄下,它會自動被檢測到。然後我們可以像注入普通屬性一樣注入其中加載的任何屬性。

因此,通過使用默認文件,我們無需顯式註冊 PropertySource,甚至不需要提供屬性文件的路徑。

我們還可以使用運行時屬性配置不同的文件,如果需要的話:

java -jar app.jar --spring.config.location=classpath:/another-location.properties

自 Spring Boot 2.3 以來,我們也可以指定配置文件的通配符位置

例如,我們可以將 spring.config.location 屬性設置為 config/*/

java -jar app.jar --spring.config.location=config/*/

這樣一來,Spring Boot 將在我們的 JAR 文件之外查找與 config/*/ 目錄模式匹配的配置文件。這在我們需要多個配置屬性源時非常有用。

自版本 2.4.0 起,Spring Boot 支持使用多文檔屬性文件,類似於 YAML 的設計

baeldung.customProperty=defaultValue
#---
baeldung.customProperty=overriddenValue

請注意,對於屬性文件,三連字符表示法必須以註釋字符(#)開頭。

4.2. 環境特定屬性文件

如果需要針對不同的環境進行配置,Boot 提供了內置機制來實現這一點。

只需在 src/main/resources 目錄下定義一個 application-environment.properties 文件,然後設置一個與環境名稱相同的 Spring 配置文件。

例如,如果定義了一個名為“staging”的環境,則需要定義一個 staging 配置文件,並使用 application-staging.properties 文件。

此 env 文件將被加載,並且 它將優先於默認屬性文件。 請注意,默認文件仍將被加載,但當存在屬性衝突時,環境特定的屬性文件將優先使用。

4.3. 測試特定屬性文件

我們可能需要在使用應用程序進行測試時,使用不同的屬性值。

Spring Boot 通過在測試運行時查找我們的 src/test/resources 目錄來處理這種情況。 再次強調,默認屬性仍然可以正常注入,但如果存在衝突,將被這些屬性覆蓋。

4.4. <em @TestPropertySource</em> 註解

如果需要對測試屬性進行更精細的控制,則可以使用 <em @TestPropertySource</em> 註解。

這允許我們為特定的測試上下文設置測試屬性,這些屬性將優先於默認屬性源。

@RunWith(SpringRunner.class)
@TestPropertySource("/foo.properties")
public class FilePropertyInjectionUnitTest {

    @Value("${foo}")
    private String foo;

    @Test
    public void whenFilePropertyProvided_thenProperlyInjected() {
        assertThat(foo).isEqualTo("bar");
    }
}

如果我們不想使用文件,我們可以直接指定名稱和值:

@RunWith(SpringRunner.class)
@TestPropertySource(properties = {"foo=bar"})
public class PropertyInjectionUnitTest {

    @Value("${foo}")
    private String foo;

    @Test
    public void whenPropertyProvided_thenProperlyInjected() {
        assertThat(foo).isEqualTo("bar");
    }
}

我們也可以通過使用 properties 參數來達到類似的效果,利用 @SpringBootTest註解:

@RunWith(SpringRunner.class)
@SpringBootTest(
  properties = {"foo=bar"}, classes = SpringBootPropertiesTestApplication.class)
public class SpringBootPropertyInjectionIntegrationTest {

    @Value("${foo}")
    private String foo;

    @Test
    public void whenSpringBootPropertyProvided_thenProperlyInjected() {
        assertThat(foo).isEqualTo("bar");
    }
}

4.5. 層次屬性

如果我們的屬性被分組在一起,我們可以利用 @ConfigurationProperties 註解,將這些屬性層次結構映射到 Java 對象圖。

讓我們以用於配置數據庫連接的一些屬性為例:

database.url=jdbc:postgresql:/localhost:5432/instance
database.username=foo
database.password=bar

然後,我們使用標註將它們映射到數據庫對象:

@ConfigurationProperties(prefix = "database")
public class Database {
    String url;
    String username;
    String password;

    // standard getters and setters
}

Spring Boot 再次採用約定優於配置的原則,自動將屬性名稱與相應的字段進行映射。我們只需要提供屬性前綴即可。

如果您想更深入地瞭解配置屬性,請查看我們的深入文章。

4.6. 替代方案:YAML 文件

Spring 也支持 YAML 文件。

所有測試特定、環境特定和默認屬性文件的命名規則都適用。唯一區別在於文件擴展名以及依賴於 SnakeYAML 庫在類路徑上的依賴。

YAML 特別適合用於存儲層次化屬性;以下屬性文件:

database.url=jdbc:postgresql:/localhost:5432/instance
database.username=foo
database.password=bar
secret: foo

以下是翻譯後的內容:

與以下 YAML 文件相同:

database:
  url: jdbc:postgresql:/localhost:5432/instance
  username: foo
  password: bar
secret: foo

此外,還值得一提的是 YAML 文件不支持 @PropertySource 註解,因此如果需要使用該註解,我們只能使用屬性文件。

另一個顯著的特點是,在 2.4.0 版本中,Spring Boot 改變了從多文檔 YAML 文件加載屬性的方式。 以前,它們添加的順序基於激活的 profile 順序。 但是,新版本中,框架遵循我們之前為 .properties 文件指示的相同排序規則:文件中聲明的屬性會覆蓋更高位置的屬性。

此外,在此版本中,profile 無法從特定 profile 文檔中激活,從而使結果更清晰、更可預測。

4.7. 導入額外配置文件

在 2.4.0 版本之前,Spring Boot 允許使用 spring.config.locationspring.config.additional-location 屬性包含額外的配置文件,但這些屬性存在一些限制。例如,它們必須在啓動應用程序之前定義(作為環境或系統屬性,或使用命令行參數),因為它們在早期階段被使用。

在上述版本中,我們可以使用 spring.config.import 屬性在 application.propertiesapplication.yml 文件中輕鬆包含額外的文件。 此屬性支持一些有用的功能:

  • 添加多個文件或目錄
  • 文件可以從類路徑或外部目錄加載
  • 指示啓動過程是否應在文件未找到時失敗,或者它是否為可選文件
  • 導入沒有擴展名的文件

讓我們來看一個有效的示例:

spring.config.import=classpath:additional-application.properties,
  classpath:additional-application[.yml],
  optional:file:./external.properties,
  classpath:additional-application-properties/

注意:我們使用換行符格式化了此屬性,僅為增強清晰度。

Spring 會將導入視為立即插入在導入聲明下方的新文檔。

4.8. 從命令行參數傳遞屬性

除了使用文件之外,我們還可以直接通過命令行傳遞屬性:

java -jar app.jar --property="value"

我們也可以通過系統屬性來完成,這些屬性在 -jar 命令之前提供,而不是之後提供:

java -Dproperty.name="value" -jar app.jar

4.9. 從環境變量中獲取屬性

Spring Boot 也會檢測環境變量,並將它們視為屬性:

export name=value
java -jar app.jar

4.10. 屬性值的隨機化

如果不想使用確定性屬性值,可以使用 <a href="https://docs.spring.io/spring-boot/docs/1.5.7.RELEASE/api/org/springframework/boot/context/config/RandomValuePropertySource.html">RandomValuePropertySource</a> 來隨機化屬性值:

random.number=${random.int}
random.long=${random.long}
random.uuid=${random.uuid}

4.11. 額外屬性源類型

Spring Boot 支持多種屬性源,並採用精心設計的排序機制,以允許合理的覆蓋。 建議參考 官方文檔,該文檔的內容比本文檔更全面。

5. 使用原始 Bean 進行配置 — PropertySourcesPlaceholderConfigurer

除了 Spring 提供的便捷方法來獲取屬性外,我們還可以手動定義和註冊屬性配置 Bean。

使用 PropertySourcesPlaceholderConfigurer 能夠完全控制配置,但同時也更冗長,並且在大多數情況下是不必要的。

下面我們將展示如何使用 Java 配置來定義此 Bean:

@Bean
public static PropertySourcesPlaceholderConfigurer properties(){
    PropertySourcesPlaceholderConfigurer pspc
      = new PropertySourcesPlaceholderConfigurer();
    Resource[] resources = new ClassPathResource[ ]
      { new ClassPathResource( "foo.properties" ) };
    pspc.setLocations( resources );
    pspc.setIgnoreUnresolvablePlaceholders( true );
    return pspc;
}

6. 屬性在父子上下文中

這個問題再次出現:當我們的 Web 應用程序有父上下文和子上下文時,會發生什麼?父上下文可能具有一些通用的核心功能和 Bean,然後一個(或多個)子上下文,可能包含 Servlet 相關的 Bean。

在這種情況下,如何定義屬性文件並在這些上下文中包含它們?以及如何從 Spring 中檢索這些屬性?

我們將提供一個簡單的分解。

如果文件 定義在父上下文中

  • @Value子上下文 中有效:是
  • @Value父上下文 中有效:是
  • environment.getProperty子上下文 中有效:是
  • environment.getProperty父上下文 中有效:是

如果文件 定義在子上下文中

  • @Value子上下文 中有效:是
  • @Value父上下文 中有效:否
  • environment.getProperty子上下文 中有效:是
  • environment.getProperty父上下文 中有效:否

7. 結論

本文介紹了在 Spring 中使用屬性和屬性文件的一些示例。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.