原文首發地址:面試官:說一說我爲何會選擇Spring Cloud Config做爲配置中心
前言
在前文中咱們詳細介紹了攜程架構部門研發的開源配置管理中心Apollo(阿波羅),經過文章咱們可知Apollo可以集中化管理應用不一樣環境、不一樣集羣的配置,配置修改後可以實時推送到應用端,而且具有規範的權限、流程治理等特性,爲咱們的平常開發帶來極大的方便。java
本文咱們將繼續介紹另外一款配置中心,它是屬於Spring Cloud嫡系的一款分佈式配置中心,它就是Spring Cloud Config。mysql
什麼是 Spring Cloud Config
1、Spring Cloud Config項目是一個解決分佈式系統的配置解決方案。它包含了Client和Server兩個部分,Server提供配置文件的存儲,以接口的形式將配置文件的內容提供出去;Client經過接口獲取數據,並依據此數據初始化本身的應用。linux
服務端也稱爲分佈式配置中心,它是一個獨立的微服務應用,用來鏈接配置倉庫併爲客戶端提供獲取配置信息、加密/解密信息等訪問接口。git
客戶端則是微服務架構中的各個微服務應用或基礎設施,它們經過指定的配置中心來管理應用資源與業務相關的配置內容,並在啓動的時候從配置中心獲取和加載配置信息。github
2、Spring Cloud Config 默認採用 Git 來存儲配置信息,因此使用 Spring Cloud Config 構建的配置服務器,自然就支持對微服務用於配置信息的版本管理,而且能夠經過 Git 客戶端工具來方便地管理和訪問配置內容。web
「注意:除了使用 Git 外,Spring Cloud Config 也一樣支持其餘存儲方式好比:SVN、本地化文件系統等。」面試
Spring Cloud Config 基本用法
首先咱們新建一個配置文件system-dev.properties,內容以下redis
jdbc.driverClassName: com.mysql.jdbc.Driver jdbc.url: jdbc:mysql://127.0.0.1:3306/testproject jdbc.username: root jdbc.password: root
而後咱們將該配置文件上傳了github,Demo地址:https://github.com/Maybe728/Spring_Cloudspring
第一步,新建一個SpringCloudConfigServer模塊sql
pom.xml代碼以下:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.cnblogs.hellxz</groupId> <artifactId>ConfigServer</artifactId> <version>1.0-SNAPSHOT</version> <parent> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-parent</artifactId> <version>Dalston.SR5</version> <relativePath/> </parent> <dependencies> <!--Spring Cloud Config 服務端依賴--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project>
經過@EnableConfigServer能夠激活配置中心服務。配置中心能夠單獨作服務,也能夠嵌入到其它服務中。推薦用單獨作服務方式使用配置中心。
package com.javaer.study; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.config.server.EnableConfigServer; /** * @Author 公衆號 | Java學習部落 **/ @SpringBootApplication @EnableConfigServer public class SpringCloudConfigServerApplication { public static void main (String[] args) { SpringApplication.run (SpringCloudConfigServerApplication.class, args); } }
因爲配置文件的存儲的多樣性,下面主要介紹Git配置形式如何配置。固然了全部的配置都配置在application.yml中。
application.yml 配置內容以下
spring: application: name: configserver cloud: config: server: git: # 配置文件只搜索url目錄下的searchPaths uri: https://github.com/Maybe728/Spring_Cloud.git # 對應 {label} 部分,即 Git 的分支 label: master # 指定搜索路徑,若是有多個路徑則使用,分隔 search-paths: springcloud-config-git/config-repo # 對於使用git,svn作爲後端配置,從遠程庫獲取配置文件,須要存儲到本地文件 basedir: /tmp/spring-cloud-repo # 配置中心經過git從遠程git庫,有時本地的拷貝被污染,這時配置中心沒法從遠程庫更新本地配置,設置force-pull=true,則強制從遠程庫中更新本地庫 force-pull: true # git 倉庫用戶名(公開庫能夠不用填寫) username: # git 倉庫密碼(公開庫能夠不用填寫) password:
spring.cloud.config.server.git.url
:指定配置文件所在遠程git庫的url地址
spring.cloud.config.server.git.label
:即 Git 的分支
spring.cloud.config.server.git.searchPaths
:和上面的參數url配合使用,定位git庫的子目錄。指定搜索路徑,若是有多個路徑則使用,分隔
spring.cloud.config.server.git.basedir
:對於使用git,svn作爲後端配置,從遠程庫獲取配置文件,須要存儲到本地文件。默認存儲在系統臨時目錄下,目錄名的前綴爲config-repo-,如在linux下時多是/tmp/config-repo-。由於/tmp下的內容有可能被誤刪,全部爲了保險,最好修改存儲目錄。若是你修改存儲目錄,你能夠修改spring.cloud.config.server.git.basedir
spring.cloud.config.server.git.force-pull
:配置中心經過git從遠程git庫讀取數據時,有時本地的拷貝被污染,這時配置中心沒法從遠程庫更新本地配置。設置force-pull=true,則強制從遠程庫中更新本地庫
最後咱們啓動程序後訪問:http://localhost:8080/system-dev.properties
「成功!!!!!」
在瀏覽器中輸入以下URL,能夠訪問到配置文件
/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties
下面經過具體例子說明以上url的意思。若是咱們的配置文件名稱system-dev.properties,則其和URL中各個字段對應的值爲:
「application: system」
「profile: dev」
搭建SpringCloudConfig客戶端
配置中心服務端配置成功後,而後其它服務從配置中心獲取配置文件,這樣的服務被稱爲**「客戶端」**。
下面咱們來搭建一個Config Client。
首先新建一個SpringCloudConfigClient項目:
「pom.xml」
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.1</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.javaer.study</groupId> <artifactId>springcloudconfigclient</artifactId> <version>0.0.1-SNAPSHOT</version> <name>springcloudconfigclient</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <spring-cloud.version>2020.0.0</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> </repository> </repositories> </project>
請將配置中心的相關配置配置在bootstrap.yml中,不要配appliaction.yml。
由於服務啓動時,會從bootstrap中讀取配置,而後從遠程配置中心讀取配置文件,最後再從appliaction中獲取配置,若是有相同的配置項,則後面的會覆蓋前面讀到的值。
因此若是配置中心的配置配置在appliaction,則配置項不會有任何效果。
「bootstrap.yml」
server: port: 8888 spring: cloud: # 配置服務器的地址 config: uri: http://127.0.0.1:8080 # 要讀取配置文件讀取的值 name: cloud-config # 若是不設置此值,則系統設置此值爲 spring.profiles.active profile: dev # 可使用以前的版本。默認值能夠是git label, branch name or commit id。可使用多個Label,多個Label可使用逗號分隔 # label: # true: 若是訪問配置中心失敗,則中止啓動服務 fail-fast: true # 配置重試,默認是重試6次,最初是延遲1s再次重試,若是再失敗,則延遲1.1*1s、1.1*1.1*1s、… 。可使用這個配置 retry: initial-interval: 2000 # 最多重試次數 max-attempts: 6 # 最大重試間隔 max-interval: 4000 # 每次重試時間是以前的倍數 multiplier: 1.2
重要參數的解釋以下:
「配置中心的url」:即從哪裏讀取配置文件,經過「spring.cloud.config.url」配置
「要讀取哪些配置文件,由如下參數共同決定」
-
「
spring.cloud.config.name
」:配置文件名稱,對應上文的讀取URL中的{applicaion}值 -
「
spring.cloud.config.profile
」:配置文件的profile,對應上文的URL中的{profile}值 -
「
spring.cloud.config.label
」:可使用以前的版本。默認值能夠是git label, branch name or commit id。可使用多個Label,多個Label可使用逗號分隔
「快速失敗」
若是要求客戶端訪問配置中心失敗,則當即中止啓動服務,則設置「spring.cloud.config.label」爲 true
「重試」
若是訪問配置失敗,則自動重試。默認是重試**「6」次,最初是延遲「1s」**再次重試,若是再失敗,則延遲1.1*1s、1.1*1.1*1s、…
。
經過下面參數能夠修改值:
「spring.cloud.config.retry.initial-interval
」:第一次失敗,延遲多久重試
「spring.cloud.config.retry.max-attempts
」:最多重試次數
「spring.cloud.config.retry.max-interval
」: 最大重試間隔
「spring.cloud.config.retry.multiplier
」: 每次重試時間是以前的倍數
「若是要實現重試功能,須要引入新的jar」
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.retry/spring-retry --> <dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> </dependency>
建立一個獲取配置信息成功後存放配置信息的對象
@Component public class JdbcConfigBean { @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; @Value("${jdbc.driverClassName}") private String driverClassName; public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getDriverClassName() { return driverClassName; } public void setDriverClassName(String driverClassName) { this.driverClassName = driverClassName; } @Override public String toString() { return "JdbcConfigBean [url=" + url + ", username=" + username + ", password=" + password + ", driverClassName=" + driverClassName + "]"; } }
建立一個Controller
package com.javaer.study; import org.springframework.web.bind.annotation.RequestMapping; /** * @author 公衆號 | Java學習部落 **/ public class SpringCloudConfigController { @RequestMapping ("/config") public JdbcConfigBean config() { return new JdbcConfigBean (); } }
最後咱們啓動**「SpringCloudConfigClient」**,在瀏覽器輸入http://127.0.0.1:8888/config,就會看到配置信息。
Spring Cloud Config 整合 Eureka 實現服務化配置中心
首先咱們須要搭建一個Eureka Server,這個不細說,由於在以前講解Eureka的時候阿里面試官問我:到底知不知道什麼是Eureka,此次,我沒沉默已經詳細的搭建過了,不會的能夠去看看,順便補充下Eureka的相關知識。
接下來咱們就要對配置中心進行改造了。
「改造服務端」
第一步引入Eureka客戶端依賴
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
第二步在配置中心中添加以下配置
eureka: instance: preferIpAddress: true client: serviceUrl: # 註冊到 eureka defaultZone: http://localhost:8761/eureka
第三步在啓動類加入@EnableDiscoveryClient激活對註冊中心支持
package com.javaer.study; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.config.server.EnableConfigServer; /** * @Author 公衆號 | Java學習部落 **/ @SpringBootApplication @EnableConfigServer @EnableDiscoveryClient public class SpringCloudConfigServerApplication { public static void main (String[] args) { SpringApplication.run (SpringCloudConfigServerApplication.class, args); } }
「服務端改造完成!!!」
「改造客戶端」
第一步一樣引入Eureka Client 依賴
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
第二步修改配置
eureka: client: serviceUrl: # 指向註冊中心的地址 defaultZone: http://127.0.0.1:8761/eureka instance: preferIpAddress: true server: port: 8888 spring: cloud: # 配置服務器的地址 config: uri: http://127.0.0.1:8080 username: user password: 111111 # 要讀取配置文件讀取的值 name: system # 若是不設置此值,則系統設置此值爲 spring.profiles.active profile: dev discovery: #表示開啓服務發現,對比上篇也主要是這裏的改變,從指定config服務地址到註冊中心服務ID enabled: true serviceId: config-serve # 可使用以前的版本。默認值能夠是git label, branch name or commit id。可使用多個Label,多個Label可使用逗號分隔 # label: # true: 若是訪問配置中心失敗,則中止啓動服務 fail-fast: true # 配置重試,默認是重試6次,最初是延遲1s再次重試,若是再失敗,則延遲1.1*1s、1.1*1.1*1s、… 。可使用這個配置 retry: initial-interval: 2000 # 最多重試次數 max-attempts: 6 # 最大重試間隔 max-interval: 4000 # 每次重試時間是以前的倍數 multiplier: 1.2
最後一步在啓動類加入@EnableDiscoveryClient激活對註冊中心支持。
「客戶端改造完成!!!」
Spring Cloud Config 健康檢查
Config Server自帶了一個健康狀態指示器,用於檢查所配置的EnvironmentRepository是否正常工做。
可以使用Config Server的/health端點查詢當前健康狀態。
默認狀況下,健康指示器向EnvironmentRepository請求的{application}是app,{profile}和{label}是對應 EnvironmentRepository實現的默認值。
對於Git,{profile}是default,{label}是master。
Spring Cloud Config 屬性覆蓋
Config Server 有一個「屬性覆蓋」的特性,它可讓開發人員爲全部的應用提供配置屬性,只須要經過 spring.cloud.config.server.overrides 屬性來設置鍵值對的參數,這些參數會以 Map 的方式加載到客戶端的配置中。
利用該特性能夠方便地爲 Spring Cloud 應用配置一些共同屬性或是默認屬性。
經過該屬性配置的參數(優先級高於 Git 倉庫裏面的配置),同時也不會被 Spring Cloud 的客戶端修改。
全部 Spring Cloud 客戶端從 Config Server 中獲取配置信息時,都會取得這些配置信息。
Spring Cloud Config 安全保護
咱們知道,通常來講,配置中心的信息都是很敏感很機密的,好比數據庫帳號密碼的配置,redis帳號密碼的配置等等,因此對配置信息作必定的安全保護是十分有必要的。
因爲微服務是構建在Spring Boot之上,因此整合Spring Security是最方便的方式。
首先在服務端引入Spring Security依賴
<dependency> <!-- spring security 安全認證 --> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
而後再配置文件中增長Spring Security配置
security: basic: enabled: true #啓用基本認證(默認) user: #配置security用戶名密碼,默認值爲「user」的用戶名和隨機生成的密碼 name: user password: 111111
啓動服務,測試一下。請求http://localhost:8080/system-dev.yml,會出現登錄界面
「成功!!!」
**「同時」咱們在「SpringCloudConfigClient」工程中,咱們修改「bootstrap.yml」配置文件(在這裏配置了Config Server的訪問信息),爲其添加認證,咱們選擇添加「spring.cloud.config.username」和「spring.cloud.config.password」**屬性
server: port: 8888 spring: cloud: # 配置服務器的地址 config: uri: http://127.0.0.1:8080 username: user password: 111111 # 要讀取配置文件讀取的值 name: system # 若是不設置此值,則系統設置此值爲 spring.profiles.active profile: dev # 可使用以前的版本。默認值能夠是git label, branch name or commit id。可使用多個Label,多個Label可使用逗號分隔 # label: # true: 若是訪問配置中心失敗,則中止啓動服務 fail-fast: true # 配置重試,默認是重試6次,最初是延遲1s再次重試,若是再失敗,則延遲1.1*1s、1.1*1.1*1s、… 。可使用這個配置 retry: initial-interval: 2000 # 最多重試次數 max-attempts: 6 # 最大重試間隔 max-interval: 4000 # 每次重試時間是以前的倍數 multiplier: 1.2
Spring Cloud Config 請求配置失敗快速響應與重試
Spring Cloud Config 的客戶端會預先加載不少其餘信息,而後再開始鏈接 Config Server 進行屬性的注入。當咱們構建的應用較爲複雜的時候,可能在鏈接 Config Server 以前花費較長的啓動時間,而在一些特殊場景下,咱們又但願能夠快速知道當前應用是否能順利地從 Config Server 獲取到配置信息,這對在初期構建調試環境時,能夠減小不少等待啓動的時間。
首先若是咱們不啓動服務端 Config-Server,直接啓動客戶端應用時 若是未配置spring.cloud.config.fail-fast=true
這個參數,在配置加載報錯以前,客戶端應用便已經加載了不少內容,好比 Controller 的請求等。
若是配置了spring.cloud.config.fail-fast=true
參數,啓動客戶端後前置的加載內容會少不少,很快就報錯。這樣有效避免了當 Config-server 配置有誤時,不須要多等待前置的一些加載時間,實現了快速返回失敗信息。
「這個就是咱們說的請求配置失敗快速響應!!!」
有時可能由於網絡波動等其餘間歇性緣由致使鏈接失敗,Config 客戶端還提供了重試功能,避免一些間歇性問題引發的失敗致使客戶端應用服務啓動的狀況。
要實現這個功能,首先咱們要在在客戶端的**「pom.xml」**中增長 spring-retry 和 spring-boot-starter-aop 依賴:
<dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
而後配置了失敗快速響應參數便可。
spring.cloud.config.fail-fast=true
重點配置解讀。
spring.cloud.config.retry.multiplier
:初始重試間隔時間(單位爲毫秒),默認值爲 1000 毫秒
spring.cloud.config.retry.initial-interval
:下一間隔的乘數,默認爲 1.1(當最初間隔爲 1000 毫秒時,下一次失敗的間隔爲 1100 毫秒)
spring.cloud.config.retry.max-interval
:最大間隔時間,默認爲 2000 毫秒
spring.cloud.config.retry.max-attempts
:最大重試此時,默認爲 6 次
Spring Cloud Config 如何實現動態刷新配置
如今咱們思考下這個問題:
若是在服務運行過程當中,咱們須要將驗證碼的失效時間從1分鐘調整爲2分鐘,那麼服務端如何在不重啓服務的狀況下就能使修改的配置動態生效呢?
這就是咱們接下來要說的**「動態刷新」**
實現動態刷新配置有兩種方式
-
使用Actuator
-
使用Spring Cloud Bus(後續會有專文介紹,再次不作講解)
接下來咱們就來使用Actuator來是實現動態刷新配置
首先咱們在客戶端的 pom.xml 中新增 spring-boot-starter-actuator 監控模塊
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
❝
spring-boot-starter-actuator 監控模塊中包含了 /refresh 端點的實現,該端點將用於實現客戶端應用配置信息的從新獲取與刷新。
❞
接着編輯 application.properties 文件,添加以下配置開啓 /refresh 端點:
management.endpoints.web.exposure.include=refresh
很簡單到這兒客戶端改造就結束了,咱們只須要重啓客戶端,而後修改git中的配置信息,在從新獲取配置信息咱們就會發現已經配置信息已經修改了。
咱們使用 /actuator/env 與 /actuator/refresh 兩個接口能夠實現單個服務實例配置的動態更新,但在微服務架構中,服務實例可能達幾十甚至幾百個,一個個調用來作動態更新就有點太不方便了。
這個時候咱們就該使用**「Spring Cloud Bus」了,本文暫時不深刻,後面會有專文解讀「Spring Cloud Bus」**。
Spring Cloud Config 總結
經過本文咱們瞭解到Spring Cloud Config項目是一個解決分佈式系統的配置管理方案。它包含了Client和Server兩個部分,server提供配置文件的存儲、以接口的形式將配置文件的內容提供出去,client經過接口獲取數據、並依據此數據初始化本身的應用。
還有Spring Cloud Config的一些核心知識點好比健康檢查,屬性覆蓋,快速響應失敗和重試以及如何實現動態刷新。
這些都是面試官說鍾愛問咱們的問題,但願經過本文咱們能對Spring Cloud Config有一個較爲全面的理解,若是想要繼續深刻,咱們還能夠去試着讀一讀它的源碼。
總之,努力總會有收穫的。
Spring Cloud 微服務精彩系列