【玩轉SpringBoot】看似複雜的Environment其實很簡單
喜歡寫程式碼,討厭配環境
我相信這十個字的小標題代表了大多數碼農的心聲。
十年前讀大學時,學校開設了C語言還有C++。但是學習這兩種語言,對於新手來說非常沒有成就感。
於是我就在校門口買個光碟,裝個VS(宇宙第一IDE),還有離線中文版MSDN(最牛的幫助文件),萬事已俱備。
學習C#語法,看類的API,然後從WinForm(視窗)開始,用滑鼠拖拽控制元件,設定控制元件屬性,觀察自動生成的程式碼,開啟人生的程式設計之路。
大四的時候接觸到Java,首先就是配置環境變數,那時覺得是一個巨複雜的東西,每次都要網上搜好一會兒才能配好。
我學習微軟的東西從來就不要配什麼環境變數,心裡很討厭這個Java的環境變數,這就導致十年後的今天,我依然要去網上搜如何配置,慚愧慚愧,哈哈。
後來發現,基本上軟體都要配置一些環境變數,只不過有的是在安裝時已經自動配好了而已,但是對於免安裝版(直接解壓)的則需要自己配。
我們也來嘗試下抽象
熟悉Java的都知道,Java裡面有兩個內建的配置集合,就是System.getenv()和System.getProperties()。
它們分別是系統環境和系統屬性,如下圖01:
一個是Map型別,一個是Properties型別,說明它們都是一些key-value形式的值。
而且Properties型別是Java裡的標準配置方式,它就對應於*.properties檔案。
至此,我們已經發現兩個問題:
1)配置項都是以key-value形式存在的。
2)配置項的來源是多樣化的,如現在的系統環境、系統屬性、配置檔案等,後期還可能會有其它。
對於配置項的多來源問題,有以下兩種方式解決:
1)可以把所有來源都暴露給使用者,這樣使用起來更加精細,但是也會帶來困擾,可能使用者也會迷糊到底該去哪個來源取值。
2)在所有來源前面加一個“門面”,只把它暴露出去,使用者看到的只是“單一來源”,就從這裡取值,其它的啥也不用知道。
Spring選擇的是第二種方案,拿到key後,只需依次去每個來源中查詢,這時只需規定下多個來源之間的優先順序順序即可。
整體可以用一個圖形表示,如下圖02:
這整體也是一種封裝變化的思想,底層的多來源問題被封裝起來,對使用者不可見。
終端使用者傳過來一個key,我給返回一個和它對應的value就行了。
來來來,認識兩個朋友
配置項在Java中通常叫做屬性,即Property。每一個來源其實就是一個源泉,即Source。
所以在Spring中就用PropertySource類來表示一個來源,如下圖03:
注意兩個欄位,name和source,name就是為每個源起個名字。source表示真正的資源,是能從中取出value的東西。
然後需要一個門面把多個來源封裝起來,如下圖04:
可以看到它裡面有一個來源的列表。這就是封裝。而且還是有順序的。
根據key取值就依次遍歷所有源即可,如下圖05:
如果所有源中都沒找到,返回null就行了。
這樣配置項(或配置屬性)的問題就已經解決了,很簡單吧。
除了配置屬性外,還有Profile
配置屬性是一個很泛化的概念,說白了它就表示以非寫程式碼的方式從外界向程式中傳遞特定的值。
它的好處就是修改起來很容易,只需修改下配置檔案或命令列引數,然後最多重啟一下就可以了。
不用修改程式碼,自然不用重新編譯,當然也不用重新打包釋出。
泛化其實就表示囊括所有的意思,但是總會有一些特殊情形,值得單獨拿出來特別對待。
如每個軟體都會至少經歷開發、測試、上線這三個階段,同樣也會有三套環境,即開發環境、測試環境、生產環境。
這裡的“環境”其實就是一個特殊情況,我們把它單獨拿出來,就叫做Profile。
對不同的環境設定不同的Profile,程式中可以讀取到Profile,這樣程式就可以適應不同的Profile,展示不同的特性。
最終就可以一套程式碼打天下。就像華為的一套作業系統適應所有的終端裝置。就像Java的一份位元組碼執行在不同的作業系統上。
在不指定Profile時,通常應該有一個預設的Profile。就像汽車預設是執行在城市道路上一樣。
在Spring中,預設的Profile就叫做default。如下圖06:
這個default可能沒有什麼意義,所以Spring提供了修改它的機會,如下圖07:
可以使用圖中的引數名稱去指定預設的Profile,以符合自己的使用習慣。
比如對於汽車這種情況,可以這樣:
spring.profiles.default=city
我們也可以為不同的環境啟用不同的Profile,Spring也提供了方法,如下圖08:
比如汽車上了高速,我們想狂野一下,可以啟用運動模式:
spring.profiles.active=sports
最後要說的就是,這個Profile可以指定多個,用逗號分隔即可。
因為Spring是用集合儲存的,所以支援多個,如下圖09:
程式在判斷哪些Profile被啟用時,可以使用邏輯表示式,這樣就更加靈活了。
支援與、或、非、括號,如下圖10:
比如我們讓程式執行在單節點debug模式,可以這樣設定:
spring.profiles.active=standalone,debug
那麼下面這些判斷將都返回true:
standalone -> true
debug -> true
standalone | debug -> true
standalone & debug -> true
!other -> true
!unknown -> true
下面這些將都返回false:
!standalone -> false
!debug -> false
standalone & other -> false
debug & unknown -> false
(standalone & other) | (debug & unknown) -> false
(standalone | debug) & other & unknown -> false
注:當同時出現與(&)、或(|)時,一定要使用括號。
那什麼是Environment呢?
很簡單,就是這個公式:
Environment = Properties + Profiles
表示Properties的介面,主要就是處理一些key-value,如下圖11:
Environment繼承了這個介面,又加入處理Profile的內容,如下圖12:
由於要支援key-value資料型別的轉換和${..}表示式的解析,所以需要能夠配置,如下圖13:
由於需要能夠以程式設計的方式啟用Profile或設定預設Profile,所以也需要能夠配置,如下圖14:
所以,這四個介面就是Spring環境的全部了。
在SpringBoot中Environment的真面目
下面是非web環境:
StandardEnvironment {activeProfiles=[], defaultProfiles=[default],
propertySources=[
ConfigurationPropertySourcesPropertySource {name='configurationProperties'},
SimpleCommandLinePropertySource {name='commandLineArgs'},
PropertiesPropertySource {name='systemProperties'},
OriginAwareSystemEnvironmentPropertySource {name='systemEnvironment'},
RandomValuePropertySource {name='random'},
OriginTrackedMapPropertySource {name='applicationConfig: [classpath:/application.yml]'},
ResourcePropertySource {name='class path resource [mode.properties]'},
ResourcePropertySource {name='class path resource [greeting.properties]'}]}
可以看到配置屬性有多個來源,包括命令列引數,系統屬性,系統環境,隨機數,yml配置檔案,properties配置檔案等。
以--開頭的引數會出現在命令列引數這個源裡,如下圖15:
以-D開頭的引數會出現在系統屬性這個源裡,如下圖16:
這些源在上面的順序就是它們的優先順序,可見命令列的最高,properties檔案的最低。
注意源中的第一個,即名稱為configurationProperties的,主要是為了適應SpringBoot的屬性名的“鬆散”繫結而專門用來處理屬性名稱的。
它並不真正提供屬性值,它的值來源於除它之外的其它源。
如果不明白什麼是屬性名的鬆散繫結的,看這個示例:
user-name, user_name, userName
這三個屬性名稱都可以繫結到一個類的userName屬性上。
下面是基於Servlet的web環境:
StandardServletEnvironment {activeProfiles=[], defaultProfiles=[default],
propertySources=[
ConfigurationPropertySourcesPropertySource {name='configurationProperties'},
SimpleCommandLinePropertySource {name='commandLineArgs'},
StubPropertySource {name='servletConfigInitParams'},
ServletContextPropertySource {name='servletContextInitParams'},
PropertiesPropertySource {name='systemProperties'},
OriginAwareSystemEnvironmentPropertySource {name='systemEnvironment'},
RandomValuePropertySource {name='random'},
OriginTrackedMapPropertySource {name='applicationConfig: [classpath:/application.yml]'},
ResourcePropertySource {name='class path resource [mode.properties]'},
ResourcePropertySource {name='class path resource [greeting.properties]'}]}
和上面的唯一區別就是多了兩個和web相關的源,就是ServletConfig和ServletContext。
可以從它們兩個裡面取出初始化引數,而且它們的優先順序僅次於命令列引數。
備註:還有一種基於Reactive(響應式)的web環境。暫時先不討論了。
每一個源裡面其實都是key-value,內容較多,不再展示。可以自己執行下試試。
本文示例程式碼:
https://github.com/coding-new-talking/playing-spring.git
>>> 玩轉SpringBoot系列文章 <<<
【玩轉SpringBoot】配置檔案yml的正確開啟姿勢
【玩轉SpringBoot】用好條件相關注解,開啟自動配置之門
【玩轉SpringBoot】給自動配置來個整體大揭祕
>>> 品Spring系列文章 <<<
品Spring:帝國的基石
品Spring:bean定義上梁山
相關推薦
【玩轉SpringBoot】看似複雜的Environment其實很簡單
喜歡寫程式碼,討厭配環境我相信這十個字的小標題代表了大多數碼農的心聲。十年前讀大學時,學校開設了C語言還有C++。但是學習這兩種語言,對於新手來說非常沒有成就感。於是我就在校門口買個光碟,裝個VS(宇宙第一IDE),還有離線中文版MSDN(最牛的幫助文件),萬事已俱備。學習C#語法,看類的API,然後從Win
【玩轉SpringBoot】配置檔案yml的正確開啟姿勢
序言在很久以前,Spring的配置檔案是基於XML的。它的名字就是applicationContext.xml,沒錯,就只有這一個xml檔案。它裡面配置了所有的東西。但是資料庫資訊通常會單獨拿出來,放入一個properties檔案,通常叫db.properties。後來覺著一個xml裡的東西實在太多了,就按功
【玩轉SpringBoot】用好條件相關注解,開啟自動配置之門
自動配置隱含兩層含義,要搞清楚上帝讓程式設計師的髮量減少,是為了讓他變得更聰明,如果有一天聰明到了極點,那就是絕頂聰明。據說在大腦高速運轉下,這樣更有利於散熱,不至於核心溫度過高而產生告警。聰明的大腦是用來思考的,現在就來深入思考和分析下自動配置。自動配置包含兩層意思,一個是配置,一個是自動。這不廢話嘛。配置
【玩轉SpringBoot】給自動配置來個整體大揭祕
上一篇文章中提到的條件註解,只是自動配置整體解決方案中的一個環節而已,可以說是管中窺豹。本文就逐步擦除迷霧,讓整體浮現出來,這樣就會有一個巨集觀的認識。除了寫程式碼之外,還能幹點什麼?提到“配置”這個詞,我們不一定知道它是什麼,但絕對知道它不是什麼,顯然,不是寫程式碼。
【玩轉SpringBoot】翻身做主人,一統web伺服器
寄人籬下的日子一直以來受傳統影響,我們的web工程總是打成war包,然後放入tomcat的webapps目錄下面。如下圖01: 當tomcat啟動時,會去解壓war包,然後執行web工程。這大家都非常熟悉了。用一個抽象的圖形表示,就是這樣子。如下圖02: 在一個大大的tomcat裡面,有一個小
【玩轉SpringBoot】讓錯誤處理重新由web伺服器接管
其實web伺服器是會處理錯誤的在web.xml還是隨處可見的年代時(確實有點老黃曆了),下面的這些配置應該都不陌生。根據錯誤程式碼處理錯誤,如下圖01: 根據異常型別處理錯誤,如下圖02: 不過我們更加熟悉的應該是SpringMVC的統一異常處理。如下圖03: 看到@Controlle
【玩轉SpringBoot】SpringBoot應用的啟動過程一覽表
SpringBoot應用的啟動方式很簡單,就一行程式碼,如下圖01: 其實這行程式碼背後主要執行兩個方法,一個是構造方法,一個是run方法。構造方法主要內容就是收集一些資料,和確認一些資訊。如下圖02: 真正的執行要從run方法開始,為此,SpringBoot特意定義了一個監聽器,專門監聽這個
【玩轉SpringBoot】通過事件機制參與SpringBoot應用的啟動過程
生命週期和事件監聽一個應用的啟動過程和關閉過程是歸屬到“生命週期”這個概念的範疇。典型的設計是在啟動和關閉過程中會觸發一系列的“事件”,我們只要監聽這些事件,就能參與到這個過程中來。要想監聽事件,首先得有事件監聽器,就是常說的Listener。下面就是Sprin
【玩轉SpringBoot】非同步任務執行與其執行緒池配置
同步程式碼寫起來簡單,但就是怕遇到耗時操作,會影響效率和吞吐量。此時非同步程式碼才是王者,但涉及多執行緒和執行緒池,以及非同步結果的獲取,寫起來頗為麻煩。不過在遇到SpringBoot非同步任務時,這個問題就不存在了。因為Spring家族是最替使用者考慮的。結果就是,像同步一樣簡單,像非同步一樣強大。眾所熟悉
【玩轉開源】BananaPi R2 —— 第二篇 Openwrt 網口配置分析
sign ati arr asi 1.0 tran spa 們的 errors 上次和大家分享了如何燒錄和安裝Openwrt到BananaPi R2,運行Openwrt的R2目前就具備路由器的功能了,這次我們來看看R2運行Openwrt的性能如何,同時也會講解一些常
【玩轉開源】Linux C 檢測網口熱插拔
int NetDetect(char *net_name, int *statue) { int ret = 0; int skfd = 0; struct ifreq ifr; skfd = socket(AF_INET, SOCK_DGRAM, 0); //建議s
【玩轉Excel】Oracle PLSQL處理生成XLSX檔案
INTRODUCTION介紹 之前發表了一個研究心得(當然是站在別人的肩膀上的),在Oracle中直接用PL/SQL解析並讀取Excel的內容。很多人都感興趣,按照我的寫法也可以成功實現了。不過,有很多朋友提出了另外一個要求:讀取Excel是可以了,那是否可以在Ora
【玩轉開源】制作Docker鏡像
沒有 名稱 登錄 我們 nan utils str oar image 做嵌入式方向經常會遇到的一個問題,就是編譯環境安裝,如果換電腦,再重新安裝環境是一個比較費時的事情,這個時候可以自己制作一個Docker鏡像,然後把編譯環境在Docker鏡像裏面配置好,以後同步環境就非
【玩轉Ubuntu】11. Ubuntu上的瀏覽檔案命令nautilus
瀏覽檔案命令nautilus 先看一下它的幫助命令 [email protected]:~$ nautilus -h 用法: nautilus [選項...] [URI...] Browse the file system with the fil
【玩轉GridView】之簡單實現隱藏列
做專案中有時候,如果設定了gridview隱藏列,問題就變得很簡單,所以小編總結了兩種實驗過的方法分享給大家。 第一種. 在gridview的RowCreated的方法中設定需要隱藏的
【玩轉GridView】之TemplateField模板
背景介紹: 近期負責開發的子系統中,很大一部分的工作都是和GridView打交道,各種編輯、刪除gridview的操作,所以小編準備系列總結,來進一步學習。 在介紹詳情之前,讓小編帶大家瞭解幾個重要角色。 介紹:在gridview 中單個欄位都會採用
【玩轉GridView】之隱藏域問題
接著上篇部落格【GridView設定隱藏列方法】來說,這次小編將介紹一種更加方便的方法: 設定隱藏域: 在Gridview加一列使用模板,在模板裡定義隱藏域HiddenField控制元件,
【玩轉Golang】slice切片的操作——切片的追加、刪除、插入等
一、一般操作 1,宣告變數,go自動初始化為nil,長度:0,地址:0,nil func main(){ var ss []string; fmt.Printf("length:%v \taddr:%p \tisnil:%v",len(ss),ss, ss==nil) } -
【玩轉開源】BananaPi R2——移植RPi.GPIO 到 R2
機會 tin 循環輸出 nal 腳本 evel 3.1 我們 api 1. 首先給大家介紹一下什麽是RPi.GPIO. 簡單去講,RPi.GPIO就是一個運行在樹莓派開發板上可以通過Python去控制GPIO的一個中間件。 現在我這邊做了一個基礎功能的移
tf.transpose函式的用法講解(多維情況,看似複雜,其實也簡單)
版權宣告:本文為博主原創文章,歡迎轉載,請標明出處。 https://blog.csdn.net/cc1949/article/details/78422704 tf.transpose函式中文意思是轉置,對於低維度的轉置問題,很簡單,不想討論,直接轉置就好(大家看下面文件,一看就懂)。 &