摘要: 原創出處 http://www.iocoder.cn/Spring-Cloud/Apollo/ 「芋道源碼」歡迎轉載,保留摘要,謝謝!
1. 概述
本文我們來學習如何在 Spring Cloud 中使用 Apollo 作爲配置中心,實現服務的統一配置管理。
Apollo(阿波羅)是攜程框架部門研發的分佈式配置中心,能夠集中化管理應用不同環境、不同集羣的配置,配置修改後能夠實時推送到應用端,並且具備規範的權限、流程治理等特性,適用於微服務配置管理場景。
在開始本文之前,胖友需要對 Apollo 進行簡單的學習。可以閱讀《Apollo 安裝部署》文章,將第一二小節看完,在本機搭建一個 Apollo 服務。
友情提示:因爲 Apollo 沒有對 Spring Cloud 進行集成,所以在使用上和在 Spring Boot 中差異性不大,因此本文內容上和《芋道 Spring Boot 配置中心 Apollo 入門》大致相同,嘿嘿~
2. 快速入門
示例代碼對應倉庫:
labx-09-sc-apollo-demo
。
本小節,我們會在 Apollo 服務中定義配置,並使用 @ConfigurationProperties
和 @Value
註解,讀取該配置。
友情提示:如果胖友看過《芋道 Spring Boot 配置文件入門》的「2. 自定義配置」小節,就會發現本小節是對標這塊的內容。
如果沒看過,也沒關係,艿艿只是提一下而已,嘿嘿。繼續往下看即可。
下面,我們來創建一個 labx-09-sc-apollo-demo
示例項目,進行快速入門。最終項目代碼如下圖所示:
2.1 引入依賴
在 pom.xml
文件中,主要引入 Apollo 相關依賴。代碼如下:
|
通過引入 apollo-client
依賴,引入 Apollo 客戶端,並實現對 Apollo 的自動化配置。
友情提示:Apollo 並未提供單獨的 Spring Boot 項目,而是在
apollo-client
中直接提供對 Apollo 在 Spring Boot 自動配置的實現。
2.2 配置文件
在 application.yml
中,添加 Apollo 配置,如下:
|
app.id
配置項,使用的 Apollo 的項目(應用)編號。稍後,我們在「2.3 創建 Apollo 配置」小節中進行創建。apollo.meta
配置項,使用的 Apollo Meta Server 地址。apollo.bootstrap.enabled
配置項,是否開啓 Apollo 配置預加載功能。默認爲false
。😈 這裏,我們設置爲true
,保證使用@Value
和@ConfigurationProperties
註解,可以讀取到來自 Apollo 的配置項。apollo.bootstrap.eagerLoad.enable
配置項,是否開啓 Apollo 支持日誌級別的加載時機。默認爲false
。😈 這裏,我們設置爲true
,保證 Spring Boot 應用的 Logger 能夠使用來自 Apollo 的配置項。apollo.bootstrap.namespaces
配置項,使用的 Apollo 的命名空間,默認爲application
。關於 Apollo 的概念,可見《Apollo 核心概念之“Namespace”》文章。
2.3 創建 Apollo 配置
在 Apollo 中創建 Apollo 配置,內容如下圖所示:
2.4 OrderProperties
創建 OrderProperties 配置類,讀取 order
配置項。代碼如下:
|
- 在類上,添加
@Component
註解,保證該配置類可以作爲一個 Bean 被掃描到。 - 在類上,添加
@ConfigurationProperties
註解,並設置prefix = "order"
屬性,這樣它就可以讀取前綴爲order
配置項,設置到配置類對應的屬性上。
2.5 DemoController
創建 DemoController 類,提供測試 @ConfigurationProperties
和 @Value
注入配置的兩個 HTTP 接口。代碼如下:
|
2.6 DemoApplication
創建 DemoApplication 類,作爲應用啓動類。代碼如下:
|
2.7 簡單測試
① 使用 DemoApplication 啓動示例應用。在 IDEA 控制檯中,可以看到 Apollo 相關的日誌如下:
|
② 使用瀏覽器,訪問 http://127.0.0.1:7070/demo/test01 接口,測試 @ConfigurationProperties
註解的配置屬性類,返回結果如下,符合預期:
|
② 使用瀏覽器,訪問 http://127.0.0.1:7070/demo/test02 接口,測試 @Value
註解的屬性,返回結果如下,符合預期:
|
3. 多環境配置
示例代碼對應倉庫:
labx-09-sc-apollo-demo-profiles
。
在《芋道 Spring Boot 配置文件入門》的「6. 多環境配置」中,我們介紹如何基於 spring.profiles.active
配置項,在 Spring Boot 實現多環境的配置功能。在本小節中,我們會在該基礎之上,實現結合 Apollo 的多環境配置。
在 Apollo 中,我們可以通過搭建不同環境的 Config Service + Admin Service 服務。然後,在每個 application-${profile}.yaml
配置文件中,配置對應的 Config Service + Admin Service 服務即可。
下面,我們來創建一個 labx-09-sc-apollo-demo-profiles
示例項目,搭建一個結合 Apollo 的多環境的示例。最終項目代碼如下圖所示:
3.1 創建 Apollo 配置
在 Apollo 中創建 Apollo 配置,創建一個 AppId 爲 demo-application-profiles
的項目,並配置 DEV(開發環境)和 PRO(生產環境)兩套配置。如下圖所示:
這裏,我們通過不同環境,使用不同 server.port
配置項。這樣, Spring Cloud 項目啓動後,從日誌中就可以看到生效的服務器端口,嘿嘿~從而模擬不同環境,不同配置。
3.2 引入依賴
和「2.1 引入依賴」一致,可以點擊 pom.xml
文件查看。
3.3 配置文件
在 resources
目錄下,創建 2 個配置文件,對應不同的環境。如下:
-
application-dev.yaml
,開發環境。app: id: demo-application-profiles # 使用的 Apollo 的項目(應用)編號 apollo: meta: http://127.0.0.1:8080 # Apollo Meta Server 地址 bootstrap: enabled: true # 是否開啓 Apollo 配置預加載功能。默認爲 false。 eagerLoad: enable: true # 是否開啓 Apollo 支持日誌級別的加載時機。默認爲 false。 namespaces: application # 使用的 Apollo 的命名空間,默認爲 application。
- 和「2.2 配置文件」不同的點,重點是
apollo.meta
配置項,設置爲 DEV 環境的 Apollo Meta Server 地址。
- 和「2.2 配置文件」不同的點,重點是
-
application-prod.yaml
,生產環境。app: id: demo-application-profiles # 使用的 Apollo 的項目(應用)編號 apollo: meta: http://127.0.0.1:18080 # Apollo Meta Server 地址 bootstrap: enabled: true # 是否開啓 Apollo 配置預加載功能。默認爲 false。 eagerLoad: enable: true # 是否開啓 Apollo 支持日誌級別的加載時機。默認爲 false。 namespaces: application # 使用的 Apollo 的命名空間,默認爲 application。
- 和「2.2 配置文件」不同的點,重點是
apollo.meta
配置項,設置爲 PROD 環境的 Apollo Meta Server 地址。
- 和「2.2 配置文件」不同的點,重點是
另外,我們會創建 application.yaml
配置文件,放不同環境的相同配置。例如說,spring.application.name
配置項,肯定是相同的啦。配置如下:
|
3.4 DemoApplication
創建 DemoApplication 類,配置 @SpringBootApplication
註解即可。代碼如下:
|
3.5 簡單測試
下面,我們使用命令行參數進行 --spring.profiles.active
配置項,實現不同環境,讀取不同配置文件。
經過測試:
- 使用命令行參數進行
--spring.profiles.active
配置,對application.yaml
配置文件無效。- 使用 VM 參數進行
-Dspring.profiles.active
配置愛,對application.yaml
配置文件有效。具體的原因還不知道,先暫時這麼解決哈~
① 開發環境示例:直接在 IDEA 中,增加 -Dspring.profiles.active=dev
到 VM options 中。如下圖所示:IDEA 配置 - dev
啓動 Spring Boot 應用,輸出日誌如下:
|
- Tomcat 啓動在 8081 端口,符合讀取 DEV 環境的配置。
② 生產環境示例:直接在 IDEA 中,增加 -Dspring.profiles.active=dev
到 VM options 中。如下圖所示:
啓動 Spring Boot 應用,輸出日誌如下:
|
- Tomcat 啓動在 8084 端口,符合讀取 PROD 環境的配置。
另外,關於 Spring Boot 應用的多環境部署,胖友也可以看看《芋道 Spring Boot 持續交付 Jenkins 入門》文章。
4. 自動刷新配置
示例代碼對應倉庫:
labx-09-sc-apollo-demo-auto-refresh
。
在上面的示例中,我們已經實現從 Apollo 讀取配置。那麼,在應用已經啓動的情況下,如果我們將讀取的 Apollo 的配置進行修改時,應用是否會自動刷新本地的配置呢?
在上面的示例中,我們已經實現從 Apollo 讀取配置。那麼,在應用已經啓動的情況下,如果我們將讀取的 Apollo 的配置進行修改時,應用是否會自動刷新本地的配置呢?答案是,針對 @Value
註解的屬性是的,針對 @ConfigurationProperties
註解的配置類需要做特殊處理。
下面,我們從「2. 快速入門」小節的 labx-09-sc-apollo-demo
項目,複製出 labx-09-sc-apollo-demo-auto-refresh
項目,用於演示 Apollo 的自動刷新配置的功能。最終項目代碼如下圖所示:
4.1 簡單測試
① 使用 DemoApplication 啓動示例應用。
② 獲得目前在 Apollo 的配置內容爲:
|
使用 curl
命令,請求 DemoController 提供的兩個測試接口,過程如下:
|
③ 修改在 Apollo 的配置內容爲:
|
此時,我們可以看到 IDEA 控制檯打印出了好多 Apollo 相關的日誌,如下:
|
- 可以看到
DemoController.payTimeoutSecond
被修改成了 480 的提示。
使用 curl
命令,請求 DemoController 提供的兩個測試接口,過程如下:
|
- 使用
@ConfigurationProperties
註解的失敗刷新,使用@Value
註解的成功刷新。
4.2 ApolloPropertiesRefresher
創建 ApolloPropertiesRefresher 類,監聽 Apollo 的配置變更,發佈 Spring Cloud EnvironmentChangeEvent 事件,從而解決 @ConfigurationProperties
註解的屬性的刷新的問題。代碼如下:
|
在 #onChange(ConfigChangeEvent changeEvent)
方法上,我們添加了 Apollo 定義的 @ApolloConfigChangeListener
註解,這樣可以實現對 Apollo 配置的監聽,從而發佈 EnvironmentChangeEvent 事件。
友情提示:更多
@ApolloConfigChangeListener
註解的分享,胖友可以閱讀《芋道 Spring Boot 配置中心 Apollo 入門》文章的「4.8 Apollo 配置監聽器」小節
4.3 重新測試
① 使用 DemoApplication 啓動示例應用。
② 獲得目前在 Apollo 的配置內容爲:
|
使用 curl
命令,請求 DemoController 提供的兩個測試接口,過程如下:
|
③ 修改在 Apollo 的配置內容爲:
|
使用 curl
命令,請求 DemoController 提供的兩個測試接口,過程如下:
|
- 使用
@ConfigurationProperties
註解的成功刷新,使用@Value
註解的成功刷新。完美~
ps:還有一種解決方案,基於 Spring Cloud RefreshScope 來解決,可以參考 SpringBootApolloRefreshConfig 的代碼,如下圖所示:
友情提示:具體的實現原理,可以閱讀《@RefreshScope 那些事》文章,艿艿暫時還沒去深入,嘿嘿~
4.4 日誌級別刷新
在「4.2 ApolloPropertiesRefresher」小節中,我們實現了監聽 Apollo 配置的變更,發佈 Spring Cloud EnvironmentChangeEvent 事件,而 Spring Cloud LoggingRebinder 會監聽該事件,重新設置日誌級別。整體流程如下圖所示:
4.5 再次測試
① 在 DemoController 類中,增加如下 API 接口。代碼如下:
|
- 如果 DemoController 對應的 Logger 日誌級別是 DEBUG 以上,則無法打印出日誌。
② 在 Apollo 中,增加 logging.level.cn.iocoder.springcloud.labx09.apollodemo.controller.DemoController
配置項爲 INFO
。
③ 使用 DemoApplication 啓動示例應用。
請求 http://127.0.0.1:8080/demo/logger 接口,控制檯並未打印日誌,因爲當前日誌級別是 INFO。
④ 在 Apollo 中,修改 logging.level.cn.iocoder.springcloud.labx09.apollodemo.controller.DemoController
配置項爲 INFO
,無需重啓應用。
請求 http://127.0.0.1:8080/demo/logger 接口,控制檯打印日誌,因爲當前日誌級別是 DEBUG。日誌內容如下:
|
- 符合預期。
5. 配置加密
示例代碼對應倉庫:
labx-09-sc-apollo-demo-jasypt
。
考慮到安全性,我們可能最好將配置文件中的敏感信息進行加密。例如說,MySQL 的用戶名密碼、第三方平臺的 Token 令牌等等。不過,Apollo 暫時未內置配置加密的功能。官方文檔說明如下:
FROM https://github.com/ctripcorp/apollo/wiki/FAQ
7. Apollo 是否支持查看權限控制或者配置加密?
從 1.1.0 版本開始,apollo-portal 增加了查看權限的支持,可以支持配置某個環境只允許項目成員查看私有 Namespace 的配置。
這裏的項目成員是指:
- 項目的管理員
- 具備該私有Namespace在該環境下的修改或發佈權限
配置方式很簡單,用超級管理員賬號登錄後,進入
管理員工具 - 系統參數
頁面新增或修改configView.memberOnly.envs
配置項即可。配置加密可以參考 spring-boot-encrypt demo項目
因此,我們暫時只能在客戶端進行配置的加解密。這裏,我們繼續採用在《芋道 Spring Boot 配置文件入門》的「8. 配置加密」小節中使用的 Jasypt。
下面,我們來創建一個 labx-09-sc-apollo-demo-jasypt
示例項目,使用 Apollo + Jasypt 搭建一個配置加密的示例。最終項目代碼如下圖所示:
5.1 引入依賴
在「2.1 引入依賴」的基礎之上,額外引入 Jasypt 相關依賴如下:
|
完整的,可以點擊 pom.xml
文件查看。
5.2 創建 Apollo 配置
在 Apollo 中創建 Apollo 配置,內容如下圖所示:
這裏爲了測試簡便,我們直接添加加密祕鑰 jasypt.encryptor.password
配置項在該 Apollo 配置中。如果爲了安全性更高,實際建議把加密祕鑰和配置隔離。不然,如果配置泄露,豈不是可以拿着加密祕鑰,直接進行解密。
5.3 配置文件
在 application.yml
中,添加 Apollo 配置,如下:
|
- 和「2.2 配置文件」一樣,就是換了一個 Apollo 項目爲
demo-application-jasypt
。
5.4 DemoApplication
創建 DemoApplication 類,作爲應用啓動類。代碼如下:
|
5.5 JasyptTest
創建 JasyptTest 測試類,使用 Jasypt 將配置項的值進行加密。代碼如下:
|
下面,我們進行下簡單測試。
① 首先,執行 #encode()
方法,手動使用 Jasypt 將 "woshimima"
和 "bushimima"
進行加密,獲得加密結果。加密結果如下:
|
② 然後,將 "woshimima"
加密結果 "yCJ8JgVNG8Ns+vikAvZBKfJu/7LVejQWzwMxyoVFoR8="
,賦值到 Apollo 的 xxx-password
配置項中。如下圖所示:
之後,執行 #print()
方法,自動使用 Jasypt 將 xxx-password
配置項解密。解密結果如下:
|
- 成功正確解密,符合預期。
5.6 DemoController
創建 DemoController 類,提供查詢 xxx-password
配置項的 HTTP 接口。代碼如下:
|
下面,我們進行下簡單測試。
① 使用 DemoApplication 啓動示例應用。
② 訪問 http://127.0.0.1:7070/demo/test 地址,返回結果爲 bushimima
,符合預期。
5.7 補充說明
目前測試下來,在將 Jasypt 集成進來時,Apollo 的「4. 自動配置刷新」功能,竟然失效了。
- 具體的驗證,胖友可以將
jasypt-spring-boot-starter
依賴設置成<scope>test</scope>
,並是使用 DemoController 進行測試。 - 具體的原因,艿艿暫時沒去調試與研究,有了解的胖友,麻煩告知下喲。在 issues#2162 中,也有其它胖友提到該問題。
如果說,胖友暫時不需要自動配置刷新功能的話,可以考慮選擇使用 Jasypt 集成。如果需要的話,那麼就等待官方支持吧,暫時不要考慮使用 Jasypt 咧。
示例代碼對應倉庫:lab-45-apollo-demo-multi。
在《芋道 Spring Boot 配置文件入門》的「9. 配置加載順序」小節,我們瞭解了 Spring Boot 自帶的配置加載順序。本小節,我們來看看來自 Apollo 的配置,在其中的順序。同時,我們將配置多個 Apollo Namespace 命名空間,看看它們互相之間的加載順序。
下面,我們來搭建一個用於測試配置加載順序的示例。
6. 配置加載順序
示例代碼對應倉庫:
labx-09-sc-apollo-demo-multi
。
在《芋道 Spring Boot 配置文件入門》的「9. 配置加載順序」小節,我們瞭解了 Spring Boot 自帶的配置加載順序。本小節,我們來看看來自 Apollo 的配置,在其中的順序。同時,我們將配置多個 Apollo Namespace 命名空間,看看它們互相之間的加載順序。
下面,我們來創建一個 labx-09-sc-apollo-demo-multi
示例項目,搭建一個用於測試配置加載順序的示例。最終項目代碼如下圖所示:labx-09-sc-apollo-demo-multi
項目
6.1 創建 Apollo 配置
在 Apollo 中創建 Apollo 配置,內容如下圖所示:
6.2 引入依賴
和「2.1 引入依賴」一致,可以點擊 pom.xml
文件查看。
6.3 配置文件
在 application.yml
中,添加 Apollo 配置,如下:
|
- 注意,我們在
apollo.bootstrap.namespaces
配置項中,設置了「6.1 創建 Apollo 配置」的兩個 Namespace 命名空間。
6.4 DemoApplication
創建 DemoApplication 類,作爲應用啓動類。代碼如下:
|
在代碼中,我們去獲取了 Spring Environment 對象,因爲我們要從其中獲取到 PropertySource 配置來源。DEBUG 運行 Application,並記得在 System.out.println(environment);
代碼塊打一個斷點,可以看到如下圖的調試信息:調試信息
- 對於
apollo.bootstrap
對應一個 CompositePropertySource 對象,即使有對應多個 Apollo Namespace。並且,多個 Namespace 是按照在apollo.bootstrap.namespaces
配置順序。 - 所有 Apollo 對應的 PropertySource 對象,優先級非常高,目前看下來僅僅低於
server.ports
對應的 MapPropertySource。基本上,我們可以認爲是最高優先級了。
6.5 補充說明
搞懂配置加載順序的作用,很多時候是解決多個配置來源,裏面配置了相同的配置項。艿艿建議的話,儘量避免出現相同配置項,排查起來還挺麻煩的。
不過所幸,在日常開發中,我們也很少會設置相同的配置項 😜。
6.6 彩蛋
至此,我們已經完成如何在 Spring Cloud 使用 Apollo 的學習。如下是 Apollo 相關的官方文檔:
如果,對源碼感興趣的胖友,可以看看《Apollo 源碼解析》噢。
如果,想要在 Spring Boot 項目中使用 Apollo 作爲配置中心的胖友,可以閱讀《芋道 Spring Boot 配置中心 Apollo 入門》文章。
7 驗證補充說明
參考「芋道源碼」技術博客,驗證完成了apollo示例代碼,並且實現了將ruoyi-cloud框架進行了apollo配置。以下是實現源碼地址:
1、文中基礎示例:https://github.com/muziye2013/SpringBoot-Labs/tree/master/labx-09
2、關於apollo多環境配置的其他參考:https://www.jianshu.com/p/94c1a5a72c5b