文章目錄
一、常規的配置設置方式
- Hardcode:寫死在代碼之中,每次修改需要發佈修改代碼,並且配置零散的存放在程序各處
- 配置文件:從代碼中提到application.yml和bootstrap.yml文件中,雖然修改後依舊要重新發布程序,但是配置被集中管理了
- 環境變量:一般情況下是通過程序啓動參數 和 系統層面的環境變量實現
- 數據庫(緩存)存儲:將參數存放到數據庫中使用,這種方式會增加數據庫的壓力
1、傳統配置管理的缺點
- 格式不統一:傳統的配置文件格式不統一,SpringBoot的有properties和yml,spring的用xml配置,再老一點的還有使用json的
- 沒有版本管理:使用配置文件還有git和svn能管理一下,存到數據庫中的 真的是改掉再也變不回來了。
- 基於靜態配置:修改、發佈的流程繁瑣,每次變動都需要在發佈
- 分佈零散:hardcode方式直接散落在代碼中,配置文件的方式好一點,但是隨之時代的進步,在分佈式的架構中配置文件的方式力不從心了,每一個模塊都有大量的配置
二、分佈式配置中心——Config
Config作爲SpringCloud官方指定產品,必然有獨到之處,在配置管理方面主要提供了三大功能
- 統一配置:提供了一箇中心化的配置方案,將各個項目中的配置內容集中在Config Server一端
- 環境隔離:Config Server提供了多種環境隔離機制,Client可以根據自身所處的項目環境(比如生產環境、測試環境)加載對應的配置文件
- 動態刷新:支持運行期改變配置屬性
除此之外,還有加密解密、定向推送等功能
1、Config的配置文件命名規則
- application:服務的名字
- profile:環境名稱
- label:對應git上不同的分支,默認爲:master(程序的git版本與之對應,可以用於配置文件的版本控制)
規則1:{application}-{profile}.yml或{application}-{profile}.properties
示例:order-dev.yml 訂單服務開發環境的配置文件
規則2:/{label}/{application}-{profile}.yml或/{label}/{application}-{profile}.properties
示例:/master/order-dev.yml 主分支下的訂單服務開發環境的配置文件
規則3:{application}/{profile}[/{label}]
2、config小demo
(1)前期準備
1)創建一個git項目
在git、碼雲或者github上創建一個新的項目,專門用來存放配置文件,我這裏命名爲:config-repo
2)在git上創建配置文件
在config-repo中創建一個文件名爲config-consumer-dev.yml
info:
profile: dev
name: Saul
words: 'God bless me'
然後提交文件,再創建一個配置文件,文件名爲config-consumer-prod.yml
info:
profile: prod
name: Paul
words: 'God bless you'
(2)服務端代碼
1)創建一個config-server(配置中心的服務模塊)模塊,修改配置文件
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
</dependencies>
2)修改配置文件
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication{
public static void main(String[] args){
new SpringApplicationBuilder(ConfigServerApplication.class)
.web(WebApplicationType.SERVLET)
.run(args);
}
}
3)創建配置文件application.yml
server:
port: 60000
spring:
application:
name: config-server
cloud:
config:
server:
#強制重載配置,把遠端上的配置覆蓋掉
overrides:
#忽略遠端上的test屬性,使用這裏的test值
test: mytest
git:
#git地址
uri: https://github.com/xxxx/config-repo.git
#git登錄名
username: 敲代碼的旺財
#git密碼
password: 真帥
#配置文件在git下的目錄,可以配置多個,主要用於區分開項目
#search-paths: test, mall
#強制拉取
force-pull: true
4)運行模塊進行測試
發送一個git請求到 http://localhost:60000/config-consumer/dev
- http://localhost:60000/:這部分是服務地址
- config-consumer/dev:這部分是配置的文件名
可以多嘗試幾種訪問:config會自動轉換格式,返回我們對應的格式
- http://localhost:60000/config-consumer-dev.yml
- http://localhost:60000/config-consumer/dev.properties
- http://localhost:60000/config-consumer/dev.json
(3)客戶端代碼
1)創建一個config-client模塊,修改配置文件
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!-- 配置中心需要他暴露端口,提供動態拉取參數的能力 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-cloud-starter-actuator</artifactId>
</dependency>
</dependencies>
2)修改配置文件
@SpringBootApplication
public class ConfigClientApplication{
public static void main(String[] args){
new SpringApplicationBuilder(ConfigClientApplication.class)
.web(WebApplicationType.SERVLET)
.run(args);
}
}
3)創建一個Controller
@RestController
//spring的註解,可以重新初始化當前對象,並且會完全的重新注入對象
@RefreshScope
public class Controller{
@Value("${name}")
public String name;
@Value("${myWords}")
public String words;
@GetMapping("/name")
public String getName(){
return name;
}
@GetMapping("/words")
public String getWords(){
return words;
}
}
4)創建配置文件application.yml
server:
port: 61000
#從配置中心獲取words屬性
myWords: ${words}
spring:
application:
name: config-client
cloud:
config:
#配置中心地址
uri: http://localhost:60000
#加載的配置文件的環境(這裏一般不是寫死的 而是通過啓動參數,或者系統環境變量來配置)
profile: prod
label: master
#指定配置文件中的application,默認的爲spring.application.name的值
name: config-consumer
#開放端口用於刷新配置文件
management:
security:
#關閉安全訪問
enabled: false
endpoints:
web:
exposure:
#開放所有端口
include: "*"
endpoint:
helth:
show-details: always
5)啓動程序,調用controller進行測試
- get請求訪問地址
http://localhost:61000/name
- 然後改變配置文件,把name屬性改掉
name: Saul and Paul
- get請求調用刷新配置的端口
http://localhost:61000/actuator/refresh
- 再次訪問地址
http://localhost:61000/name
三、高可用配置中心
1、實現原理
現在的配置中心是單節點的,所有的服務都連接在這個單節點的配置中心上,如果配置中心宕機了,那所有服務的配置就不能更新了,我們將配置中心搭建成集羣,在服務和配置中心集羣中間,搭建一個負載均衡器,如果一個配置中心的節點宕機了,負載均衡器將請求轉到還存活的節點上
2、藉助Eureka實現高可用配置中心
(1)服務端代碼修改
1)創建一個config-server(配置中心的服務模塊)模塊,修改配置文件
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
2)修改配置文件
@SpringBootApplication
@EnableConfigServer
@EnableDiscoveryClient
public class ConfigServerApplication{
public static void main(String[] args){
new SpringApplicationBuilder(ConfigServerApplication.class)
.web(WebApplicationType.SERVLET)
.run(args);
}
}
3)創建配置文件application.yml
server:
port: 60000
eureka:
client:
serviceUrl:
defaultZone: http://localhost:20000/eureka/
spring:
application:
name: config-server
cloud:
config:
server:
git:
#git地址
uri: https://github.com/xxxx/config-repo.git
#git登錄名
username: 敲代碼的旺財
#git密碼
password: 真帥
#配置文件在git下的目錄,可以配置多個,主要用於區分開項目
#search-paths: test, mall
#強制拉取
force-pull: true
這裏可以啓動多個config-server,改下端口號就行了
(2)客戶端代碼修改
1)創建一個config-client模塊,修改配置文件
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!-- 配置中心需要他暴露端口,提供動態拉取參數的能力 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-cloud-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
2)修改啓動類
@SpringBootApplication
@EnableDiscoveryClient
public class ConfigClientApplication{
public static void main(String[] args){
new SpringApplicationBuilder(ConfigClientApplication.class)
.web(WebApplicationType.SERVLET)
.run(args);
}
}
4)創建配置文件application.yml
server:
port: 61000
#從配置中心獲取words屬性
myWords: ${words}
eureka:
client:
serviceUrl:
defaultZone: http://localhost:20000/eureka/
spring:
application:
name: config-client
cloud:
config:
discovery:
#啓動服務發現功能
enabled: true
service-id: config-server-eureka
#加載的配置文件的環境(這裏一般不是寫死的 而是通過啓動參數,或者系統環境變量來配置)
profile: prod
label: master
#指定配置文件中的application,默認的爲spring.application.name的值
name: config-consumer
#開放端口用於刷新配置文件
management:
security:
#關閉安全訪問
enabled: false
endpoints:
web:
exposure:
#開放所有端口
include: "*"
endpoint:
helth:
show-details: always
四、配置加密
數據庫密碼是一個相當機密的信息,儘量不要讓安全級別不高的個人或團隊直接接觸到。儘管我們程序猿們個個都是信得過的,不會隨便登錄生產環境做破壞性操作,可也不能保證突發事件的發生。比如今天我和產品經理幹了一架,打輸了,氣不過,拿着密碼登錄生產環境刪庫跑路了。
我們需要引入一個數據安全機制,減少敏感數據的暴露程度,因此需要對三個環節做嚴格控制。
數據加密端 就像頒發CA證書一樣,必須由一箇中心機構用密鑰對明文進行加密。這裏也一樣,需要在生產環境中創建一個特定的服務,專門做加密操作。最重要的是,加密所用的祕鑰只能保存在那臺機器裏,不能對外暴露數據存放端 數據存放端(如GitHub)只能保存加密過後的數據數據解密端 由於密鑰都保存在數據加密端,因此數據解密和數據加密必須放在同一個地方進行,加密數據在傳給客戶端之前要經過解密,不能將祕鑰下放到客戶端機器上進行解密。
我們需要引入一個數據安全機制,減少敏感數據的暴露程度,因此需要對三個環節做嚴格控制
- 數據加密端:就像頒發CA證書一樣,必須由一箇中心機構用密鑰對明文進行加密。這裏也一樣,需要在生產環境中創建一個特定的服務,專門做加密操作。最重要的是,加密所用的祕鑰只能保存在那臺機器裏,不能對外暴露
- 數據存放端:數據存放端(如GitHub)只能保存加密過後的數據
- 數據解密端:由於密鑰都保存在數據加密端,因此數據解密和數據加密必須放在同一個地方進行,加密數據在傳給客戶端之前要經過解密,不能將祕鑰下放到客戶端機器上進行解密
1、加密Demo
(1)修改jdk的jce主鍵
- 在Oracle的官網下載jce
https://www.oracle.com/java/technologies/javase-jce-all-downloads.html
只有jdk6/7/8並且版本低於6u16/7u171/8u161,才需要下載 - 下載的文件解壓,得到loacl_policy.jar和US_export_policy.jar,將解壓後的文件拷貝到
java目錄\jre\lib\security
下,覆蓋同名文件
(2)config-server修改bootstrap.yml配置文件
encrypt:
#加密用的key,隨便寫
key: keyboardDog
發送一個get無參請求到localhost:60001/encrypt/status
上,測試配置是否成功
(3)對字符串進行加密/解密
- 加密
發送一個post請求到localhost:60001/encrypt
上,使用row傳參,參數直接填寫想要加密的字符串 - 解密
發送一個post請求到localhost:60001/dencrypt
上,使用row傳參,參數直接填寫加密過後的字符串
(4)修改github上的配置文件
info:
profile: prod
name: Paul
#這裏把字符串換掉,{cipher} 表示這個字符串需要解密 ,後面跟上加密過後的字符串
words: '{cipher}xxxxxxxxxxxxxxxxxxxxx'