《Spring Boot 源碼學習系列》
初識 ConfigurableEnvironment
- 一、引言
- 二、主要內容
- 2.1 Environment
- 2.1.1 配置文件(profiles)
- 2.1.2 屬性(properties)
- 2.2 ConfigurablePropertyResolver
- 2.2.1 屬性類型轉換配置
- 2.2.2 占位符配置
- 2.2.3 值分隔符配置
- 2.2.4 必需屬性驗證配置
- 2.3 ConfigurableEnvironment
- 2.3.1 接口方法
- 2.3.2 具體實現
- 三、總結
一、引言
上篇博文,Huazie 帶大家深入分析下 ApplicationArguments
接口及其默認實現。在初始化完 ApplicationArguments
之后,Spring Boot 就開始通過 prepareEnvironment
方法對 ConfigurableEnvironment
對象進行初始化操作。在介紹 ConfigurableEnvironment
的初始化之前,我們有必要先認識一下 ConfigurableEnvironment
接口。
二、主要內容
注意: 以下涉及 Spring Boot 源碼 均來自版本 2.7.9,其他版本有所出入,可自行查看源碼。
下面貼出 ConfigurableEnvironment
的源碼:
public interface ConfigurableEnvironment extends Environment, ConfigurablePropertyResolver {void setActiveProfiles(String... profiles);void addActiveProfile(String profile);void setDefaultProfiles(String... profiles);MutablePropertySources getPropertySources();Map<String, Object> getSystemProperties();Map<String, Object> getSystemEnvironment();void merge(ConfigurableEnvironment parent);
}
從上述源碼,可以看出 ConfigurableEnvironment
接口繼承了 Environment
和 ConfigurablePropertyResolver
接口,它們其實最終都繼承自 PropertyResolver
接口。
2.1 Environment
org.springframework.core.env.Environment
表示當前應用程序在其中運行的環境。它模擬了應用程序環境的兩個關鍵方面:
2.1.1 配置文件(profiles)
Profile
是一個命名的、邏輯上的 bean 定義組,這些定義只有在給定的配置文件處于活動狀態時才會被注冊到容器中。通過 Environment
可以確定哪些配置文件(如果有)當前是活動的,以及哪些配置文件(如果有)應該默認是活動的。可以使用 @Profile
注解來指定 bean 應該在哪個配置文件下被注冊。
2.1.2 屬性(properties)
屬性有各種來源,如屬性文件、JVM 系統屬性、系統環境變量、JNDI、servlet 上下文參數、臨時的 Properties 對象、Map 等。Environment
對象為用戶提供了一個方便的服務接口,用于配置屬性源并從這些源中解析屬性。通過 Environment
,可以方便地訪問和解析這些屬性,而無需直接操作這些源。
此外,Environment
接口還繼承了 PropertyResolver
接口【用于根據任何底層源解析屬性的接口】,這意味著它還提供了與屬性訪問相關的功能。
2.2 ConfigurablePropertyResolver
org.springframework.core.env.ConfigurablePropertyResolver
也繼承了 PropertyResolver
接口,并在其基礎上增加了更多的配置選項:
2.2.1 屬性類型轉換配置
ConfigurablePropertyResolver
提供了基于 org.springframework.core.convert.ConversionService
的屬性類型轉換功能。ConversionService
是 Spring 中用于類型轉換的接口,它允許將一種類型的對象轉換為另一種類型的對象。
與之關聯的方法如下:
getConversionService()
: 獲取當前用于類型轉換的ConfigurableConversionService
實例。setConversionService(ConfigurableConversionService conversionService)
: 設置用于類型轉換的ConfigurableConversionService
實例。這允許用戶自定義類型轉換的邏輯,以滿足特定的應用程序需求。
2.2.2 占位符配置
ConfigurablePropertyResolver
允許開發者配置占位符的前綴和后綴。默認情況下,前綴是 ${
,后綴是 }
。占位符的值本身也可以包含其他占位符,形成嵌套占位符,ConfigurablePropertyResolver
支持嵌套占位符的解析。
與之相關的方法如下:
setPlaceholderPrefix(String placeholderPrefix)
: 設置占位符的前綴。在解析屬性時,這些前綴將被用來識別需要替換的占位符。setPlaceholderSuffix(String placeholderSuffix)
: 設置占位符的后綴。與前綴一起,它們定義了占位符的完整格式。setIgnoreUnresolvableNestedPlaceholders(boolean ignoreUnresolvableNestedPlaceholders)
: 設置是否忽略無法解析的嵌套占位符。如果設置為true
,則當遇到無法解析的嵌套占位符時,解析器將不會拋出異常,而是繼續執行。
2.2.3 值分隔符配置
值分隔符是指在解析屬性值時,用于分隔占位符與其關聯默認值的字符設置。
比如,在配置文件中有這樣的屬性值:${propertyName:defaultValue}
。
在這里 propertyName
是占位符,而 defaultValue
是在 propertyName
無法解析時使用的默認值。那顯然在上述示例中,:
就是 值分隔符。
與之相關的方法如下:
setValueSeparator(@Nullable String valueSeparator)
: 設置值分隔符。在某些情況下,屬性值可能包含多個值,這些值由分隔符分隔。此方法允許用戶指定分隔符。
2.2.4 必需屬性驗證配置
必需屬性驗證配置是 Spring 框架中用于確保應用程序配置中包含某些關鍵屬性的一種機制。
與之相關的方法如下:
setRequiredProperties(String... requiredProperties)
: 設置必需的屬性。這些屬性必須在解析過程中存在,否則驗證將失敗。validateRequiredProperties() throws MissingRequiredPropertiesException
: 驗證是否所有必需的屬性都已設置。如果任何必需屬性缺失,此方法將拋出MissingRequiredPropertiesException
異常。
2.3 ConfigurableEnvironment
了解了 Environment
和 ConfigurablePropertyResolver
,我們再來看看 ConfigurableEnvironment
。
2.3.1 接口方法
ConfigurableEnvironment
代表了一個可配置的環境,其定義了如下的方法:
setActiveProfiles(String... profiles)
:設置當前激活的Profile
組集合。在Spring 中,Profile
允許用戶根據特定的環境(如開發、測試、生產)加載不同的配置。通過傳遞一個或多個Profile
名稱作為參數,你可以激活這些Profile
。addActiveProfile(String profile)
:向當前激活的Profile
組集合中添加一個Profile
組。setDefaultProfiles(String... profiles)
:設置默認激活的Profile
組集合。激活的Profile
組集合為空時,會默認實用默認的Profile
組集合。getPropertySources()
:返回當前環境的MutablePropertySources
對象。PropertySources
是一個包含多個PropertySource
的列表,每個PropertySource
都可以提供屬性。MutablePropertySources
允許你添加、替換或刪除PropertySource
。getSystemProperties()
:返回 Java 系統屬性的映射。這些屬性是 JVM 啟動時通過-D
參數或系統屬性文件(如system.properties)設置的。getSystemEnvironment()
:返回操作系統環境變量的映射。這些變量通常包含關于系統配置和運行時的信息。merge(ConfigurableEnvironment parent)
:將父ConfigurableEnvironment
的屬性源合并到當前環境中。合并時,父環境的屬性源將添加到當前環境的屬性源列表的開頭,從而允許它們覆蓋當前環境的任何同名屬性。
2.3.2 具體實現
org.springframework.core.env.AbstractEnvironment
是一個抽象類,實現了 ConfigurableEnvironment
接口,為環境配置(如屬性源和概要文件管理)提供了基本的支持
org.springframework.core.env.StandardEnvironment
繼承自 AbstractEnvironment
,應用于非 Web 環境。它是 Spring 中默認的環境配置類,負責讀取系統屬性、環境變量以及配置文件中的配置信息,并將其封裝在一個 PropertySources
對象中供 Spring 應用程序使用。
org.springframework.web.context.support.StandardServletEnvironment
繼承自 StandardEnvironment
,它是基于 Servlet 的 Web 應用程序要使用的 Environment 實現。所有基于 Servlet 的 Web 相關的 ApplicationContext
類都會默認初始化一個實例。提供 ServletConfig
、ServletContext
和基于 JNDI 的 PropertySource
實例。在初始化過程中,會根據 ServletContext
和 ServletConfig
的可用性來初始化和配置屬性源。通過 customizePropertySources()
方法,可以自定義屬性源的添加順序和配置方式。
org.springframework.mock.env.MockEnvironment
繼承自 AbstractEnvironment
,它用于測試目的,可以模擬環境變量和系統屬性的值。
三、總結
本篇博文 Huazie 同大家一起了解了 ConfigurableEnvironment
接口和其父接口,這些對于后續理解 ConfigurableEnvironment
的初始化操作至關重要。接下來的博文將會繼續聚焦 Spring Boot 啟動運行階段,敬請期待!!!