Environment的中文意思是環境,它表示整個spring應用運行時的環境資訊,它包含兩個關鍵因素
- profiles
- properties
profiles
profiles這個概念相信大家都已經理解了,最常見的就是不同環境下,決定當前spring容器中的不同配置背景關系的解決方案,比如針對開發環境、測驗環境、生產環境,構建不同的application.properties配置項,這個時候我們可以通過profiles這個屬性來決定當前spring應用背景關系中生效的配置項,
實際上,通過profiles可以針對bean的配置進行邏輯分組, 簡單來說,我們可以通過profiles來針對不同的bean進行邏輯分組,這個分組和bean本身的定義沒有任何關系,無論是xml還是注解方式,都可以配置bean屬于哪一個profile分組,
當存在多個profile分組時,我們可以指定哪一個profile生效,當然如果不指定,spring會根據默認的profile去執行,我們來通過一個代碼演示一下,
ProfileService
創建一個普通的類,代碼如下
public class ProfileService {
private String profile;
public ProfileService(String profile) {
this.profile = profile;
}
@Override
public String toString() {
return "ProfileService{" +
"profile='" + profile + '\'' +
'}';
}
}
宣告一個配置類
在配置類中,構建兩個bean,配置不同的profile,
@Configuration
public class ProfileConfiguration {
@Bean
@Profile("dev")
public ProfileService profileServiceDev(){
return new ProfileService("dev");
}
@Bean
@Profile("prod")
public ProfileService profileServiceProd(){
return new ProfileService("prod");
}
}
定義測驗方法
public class ProfileMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext();
// applicationContext.getEnvironment().setActiveProfiles("prod");
applicationContext.register(ProfileConfiguration.class);
applicationContext.refresh();
System.out.println(applicationContext.getBean(ProfileService.class));
}
}
可以通過很多種方式來激活配置,默認情況下不添加applicationContext.getEnvironment().setActiveProfiles("prod");時,會發現bean沒有被裝載,添加了之后,會根據當前激活的profiles來決定裝載哪個bean,
除此之外,我們還可以在啟動引數中增加-Dspring.profiles.active=prod來決定當前激活哪個profile,該屬性可以配置在系統環境變數、JVM系統屬性、等,
注意組態檔不是單選;可能會同時激活多個組態檔,編程式的使用方法setActiveProfiles(),該方法接收String陣列引數,也就是多個組態檔名
applicationContext.getEnvironment().setActiveProfiles("prod","dev");
如果沒有任何profile配置被激活,默認的profile將會激活,
默認profile組態檔可以更改,通過環境變數的setDefaultProfiles方法,或者是宣告的spring.profiles.default屬性值
profiles總結
簡單總結一下profiles,通過profiles可以最一組bean進行邏輯分組,這些邏輯分組的bean會根據Environment背景關系中配置的激活的profile來進行加載,也就是Environment對于profiles配置來說,它能決定當前激活的是哪個profile配置,
-
一個profile就是一組Bean定義的邏輯分組,
-
這個分組,也就 這個profile,被賦予一個命名,就是這個profile名字,
-
只有當一個profile處于active狀態時,它對應的邏輯上組織在一起的這些Bean定義才會被注冊到容器中,
-
Bean添加到profile可以通過XML定義方式或者annotation注解方式,
-
Environment對于profile所扮演的角色是用來指定哪些profile是當前活躍的預設,
Properties
properties的作用就是用來存放屬性的,它可以幫我們管理各種配置資訊,這個配置的來源可以是properties檔案、JVM properties、系統環境變數、或者專門的Properties物件等,
我們來看一下Environment這個介面,它繼承了PropertyResolver,這個介面和屬性的操作有關,也就是我們可以通過Environment來設定和獲得相關屬性,
public interface Environment extends PropertyResolver {
String[] getActiveProfiles();
String[] getDefaultProfiles();
/** @deprecated */
@Deprecated
boolean acceptsProfiles(String... var1);
boolean acceptsProfiles(Profiles var1);
}
至此,我們可以可以簡單的總結Environment的作用,Environment提供了不同的profile配置,而PropertyResolver提供了配置的操作,由此我們可以知道,Spring 容器可以根據不同的profile來獲取不同的配置資訊,從而實作Spring容器中運行時環境的處理,
environment的應用
-
在spring boot應用中,修改application.properties配置
env=default -
創建一個Controller進行測驗
@RestController public class EnvironementController { @Autowired Environment environment; @GetMapping("/env") public String env(){ return environment.getProperty("env"); } }
指定profile屬性
在前面的內容中我們介紹了profile和property這兩個概念,現在我們來結合使用加深對這兩者的理解,
在spring boot應用中,默認的外部化配置是application.properties檔案,事實上,除了這個默認的組態檔之外,我們還可以使用springboot中的約定命名格式來實作不同環境的配置
application-profile.properties
當前spring boot應用選擇使用哪個properties檔案作為背景關系環境配置,取決與當前激活的profile,同樣,我們可以通過很多種方式來激活,比如在application.properties中增加spring.profiles.active=dev這種方式,也可以在JVM引數中增加該配置來指定生效的配置,
在不指定的情況下,則使用默認的組態檔,簡單來說,如果沒有顯式激活某一個組態檔,那么應用程式就將加載application-default.properties中的屬性,
這個功能非常實用,一般的公司里面都會有幾套運行環境,比如開發、測驗、生產環境,這些環境中會有一些配置資訊是不同的,比如服務器地址,那我們需要針對不同的環境使用指定的配置資訊,通過這種方式就可以很方便的去解決,
@Value注解的使用
在properties檔案中定義的屬性,除了可以通過environment的getProperty方法獲取之外,spring還提供了@Value注解,
@RestController
public class EnvironementController {
@Value("${env}")
private String env;
@GetMapping("/env")
public String env(){
return env;
}
}
spring容器在加載一個bean時,當發現這個Bean中有@Value注解時,那么它可以從Environment中將屬性值進行注入,如果Environment中沒有這個屬性,則會報錯,
Spring Environment原理設計
結合前面咱們講過的內容,我們來推測一下Environment的實作原理,
簡單演示一下Environment中的配置來源
- @Value("${java.version}") 獲取System.getProperties , 獲取系統屬性
- 配置command的jvm引數,
-Denvtest=command
基于現有的內容的推導,我們可以畫出下面這樣一個圖,

- 第一部分是屬性定義,這個屬性定義可以來自于很多地方,比如application.properties、或者系統環境變數等,
- 然后根據約定的方式去指定路徑或者指定范圍去加載這些配置,保存到記憶體中,
- 最后,我們可以根據指定的key從快取中去查找這個值,
下面這個是表示Environment的類關系圖,這個類關系圖還是非常清晰的體現了Environment的原理,

上述類圖的核心API說明如下
-
Environment介面,繼承了PropertyResolver, PropertyResolver,它主要有兩個作用,
-
通過
propertyName屬性名獲取與之對應的propertValue屬性值(getProperty), -
把
${propertyName:defaultValue}格式的屬性占位符,替換為實際的值(resolvePlaceholders),
-
-
PropertyResolver的具體實作類是PropertySourcesPropertyResolver,屬性源的解決方案,該類是體系中唯一的完整實作類,它以PropertySources屬性源集合(內部持有屬性源串列List
)為屬性值的來源,按序遍歷每個PropertySource,獲取到一個非null的屬性值則回傳,
其中,PropertySourcesPropertyResolver中的List

著作權宣告:本博客所有文章除特別宣告外,均采用 CC BY-NC-SA 4.0 許可協議,轉載請注明來自
Mic帶你學架構!
如果本篇文章對您有幫助,還請幫忙點個關注和贊,您的堅持是我不斷創作的動力,歡迎關注「跟著Mic學架構」公眾號公眾號獲取更多技術干貨!

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/430156.html
標籤:Java
