Spring Boot項目代碼開發過程中有這樣一個原則:“約定大於配置”,SpringBoot為我們提供了properties和yml類型的文件供我們編寫配置文件,而這些配置文件的編寫是要遵循約定,這樣一來,就有了一個統一的規范,使得我們在使用任何第三方組件時,都能按照規則配置文件,減少耦合。
因此,我們在微服務開發時,會接觸到大量的配置,其中有的配置是基礎配置,也就是項目要跑起來所需的配置,或者第三方組件要用到的默認配置;同時也有些配置是我們業務需要的,是我們程序員自己定義的。基礎配置一般在項目運行之后不會輕易修改,但是自定義配置可能會因為業務的需要而進行修改,例如:一個打折促銷業務,在配置文件中配置了一個【折扣】屬性,需要在某個節日提高折扣力度,更改折扣數值。基於項目在運行過程中不能輕易重啟這個前提下,想要修改配置則是一個難題。然而Spring Cloud Config幫我們解決了這個問題,它可以實現配置文件的熱更新。
Spring Cloud Config原理
各個微服務不用在自己的項目代碼中維護配置文件,而是將配置文件統一存儲到第三方,一般是用git存儲,但也可以是svn、本地文件等。配置中心服務(服務端,Spring Cloud Config所定義的一個拉取配置文件的服務)會從這些地方拉取最新的配置,而其他微服務(客戶端)只需從配置中心服務拉取最新配置即可
Spring Cloud Config入門
最簡單的配置中心,就是僅僅啟動一個服務作為配置中心服務端。這里我選擇git來存儲配置文件
首先需要在git上創建一個倉庫,保存各種配置文件,如圖:
其中config-client-dev.yml的內容如下:
user:
username: config-dev
password: 0
這里的配置文件名稱是有規律的,去掉后綴"-dev"前面的內容是配置中心客戶端的服務名
創建配置中心服務端
1.新建項目,引入依賴
新建一個Spring Boot微服務config-center,這個微服務需要被Spring cloud管理,需根據需要設定版本,希望讀者對Spring Cloud的使用已經有了基本的了解。引入依賴:
<!-- spring cloud config 服務端包 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
2.編寫配置文件
這里與之前創建微服務不同,我們需要創建一個bootstrap.yml文件,bootstrap.yml在Spring Boot 啟動時會優先於application.yml被執行,它在程序引導時執行,應用於更加早期配置信息讀取。內容如下:
spring:
application:
name: config-center
cloud:
config:
server:
git:
uri: https://github.com/ithushuai/config-center-demo #配置文件所在倉庫
username: git用戶名
password: git密碼
default-label: master #配置文件分支
search-paths: config #配置文件所在根目錄
timeout: 10 # 超時時間,單位s,可以設置長一點,國內訪問github比較慢,極容易出現訪問超時
再創建application.yml文件,內容如下:
server:
port: 8084
3.編寫啟動類,加上@EnableConfigServer注解
@SpringBootApplication
@EnableConfigServer
public class ConfigApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigApplication.class, args);
}
}
4.啟動服務,訪問git倉庫中的配置文件。有如下一些訪問規則:
/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties
application:服務名
profile:配置環境(dev、prod、test...)
label:git分支,默認master
例如想要訪問config-single-client-dev.yml,就可以按規則訪問如下接口:
http://localhost:8084/config-client-dev.yml
在瀏覽器中訪問該接口,能夠獲取配置文件內容,就說明配置中心服務端已經搭建好了
創建配置中心客戶端
上述步驟走完,說明配置中心服務端已經搭建好,並且可用,現在需要搭建一個客戶端服務來測試能否從服務端拉取配置
1.創建項目,引入依賴
<!-- spring cloud config 客戶端包 -->
<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-boot-starter-actuator</artifactId>
</dependency>
2.編寫配置文件
bootstrap.yml:
# 必須使用bootstrap.yml定義這些配置,cloud config會默認加載這個配置文件中的配置
spring:
profiles:
active: dev
---
spring:
profiles: dev
application:
name: config-client
cloud:
config:
uri: http://localhost:8084
label: master
profile: dev
---
spring:
profiles: prod
application:
name: config-client
cloud:
config:
uri: http://localhost:8084
label: master
profile: prod
application.yml:
server:
port: 8085
3.編寫啟動類,常規Spring Boot項目啟動類
@SpringBootApplication
public class ConfigClientApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigClientApplication.class, args);
}
}
4.編寫一個Controller類,並注入自定義配置,來測試能否獲取配置文件屬性
@RestController
public class GitController {
@Value("${user.password}")
private String password;
@RequestMapping("/show")
public String getGitConfig(){
return password;
}
}
5.啟動項目,在瀏覽器中訪問http://localhost:8085/show,頁面顯示“0”,則表明可以正常獲取配置屬性
自動刷新配置
如果我們修改git倉庫中配置文件的內容,比如將password改為1,此時瀏覽器訪問:http://localhost:8084/config-client-dev.yml
會發現結果更新為“1”,然而我們再訪問:http://localhost:8086/show,結果仍然為“0”。也就是說當git倉庫中的配置文件被修改后,配置中心客戶端並不能察覺出變化,這並沒有達到我們的初衷。要實現客戶端刷新配置文件,則需要actuator的支持,前面客戶端引入的spring-boot-starter-actuator就是為了使用actuator。做法如下:
1.在注入配置文件屬性的類上加上@RefreshScope注解
Controller類中注入了配置文件,因此在GitController類上加上@RefreshScope注解
@RestController
@RefreshScope //開啟刷新功能,在使用到配置的類上加。不使用bus時,使用當前服務地址,單獨訪問http://localhost:8085/actuator/refresh,即可實現本服務配置刷新
public class GitController {
@Value("${user.password}")
private String password;
@RequestMapping("/show")
public String getGitConfig(){
return password;
}
}
2.在application.yml中引入management配置文件,暴露actuator的接口
server:
port: 8085
management:
endpoints:
web:
exposure:
include: "*"
加了以上配置,我們就可以使用actuator給我們提供的一些接口,例如/actuator/refresh
我們用postman測試http://localhost:8085/actuator/refresh接口,使用POST請求:
如圖,一旦配置文件發生變化,接口返回值中就會有相應的提示,上述內容表明config-client的版本有更新,發生變化的屬性是user.password
此時瀏覽器再訪問http://localhost:8086/show,結果已經更新為1
上述自動刷新的弊端
實際生產環境中,會有很多個微服務,假如涉及到多個服務的配置修改,又或者某個服務部署了在了多個服務器上進行負載均衡,這時就需要手動為刷新每個服務,因為只刷新某一個服務,其他服務是不會實現自動刷新的。
配合Spring Cloud Bus實現自動刷新所有服務
Spring Cloud Bus的核心原理就是利用消息隊列做廣播,可以支持RabbitMQ以及Kafka。這里使用RabbitMQ做消息中間件,前提需要安裝好RabbitMQ。
1.在配置中心服務端增加bus依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
2.在application.yml中加入rabbitmq的配置
spring:
rabbitmq:
host: 192.168.18.130
username: admin
password: admin
3.在客戶端服務中同樣增加bus依賴和rabbitmq的配置
4.啟動兩個客戶端服務,分別設置啟動端口為8085,8086
可以在IDEA工具中設置啟動參數,步驟如下:
1)在右上角點擊Edit Configurations
2)設置VM options:
3)當前頁面左上角點擊復制按鈕,復制一個啟動參數,並設置端口為8086
5.啟動兩個客戶端服務,在瀏覽器中分別訪問 http://localhost:8085/show,http://localhost:8086/show,顯示的結果與github上一致。此時,修改config-client-dev.yml中password的值為2,postman訪問配置中心服務的bus-refresh接口,注意這里是bus-refresh:http://localhost:8084/actuator/bus-refresh,請求方式為POST,請求成功postman不顯示任何內容
6.再次訪問兩個客戶端的接口,發現數據都做了刷新
在Eureka的管理下使用Spring Cloud Config
Spring cloud Config + Spring Cloud Bus已經可以實現配置文件的集中化管理,並且能夠實現配置文件自動刷新。但是基於Spring Cloud的分布式服務往往是由Eureka來對各個微服務進行管理,那么如何將Spring Cloud Config集成到Eureka注冊中心中去呢?以下步驟建立在Eureka注冊中心已經搭建好的基礎上
1.在配置中心服務中增加Euraka客戶端的依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2.在啟動類上加上@EnableDiscoveryClient注解
@SpringBootApplication
@EnableConfigServer
@EnableDiscoveryClient
public class ConfigApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigApplication.class, args);
}
}
3.配置文件中添加Eureka的配置
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
4.客戶端服務中增加Eureka客戶端依賴,啟動類上加上@EnableDiscoveryClient注解,在bootstrap.yml中加上Eureka配置,並修改config的配置,如下
eureka: # 這里eureka配置必須放在bootstrap.yml中,因為在項目啟動時,就需要注冊到注冊中心,然后去配置中心拉取配置,有先后順序
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
spring:
profiles:
active: dev
---
spring:
profiles: dev
application:
name: config-client
cloud:
config:
label: master
profile: dev
discovery: # 當config server注冊到eureka時配置
enabled: true
service-id: config-center # config server 在注冊中心的注冊名
---
spring:
profiles: prod
application:
name: config-client
cloud:
config:
# uri: http://localhost:8084 # 當不使用eureka注冊中心時,用uri配置config server的地址,當config server注冊到eureka時,無需該配置
label: master
profile: prod
discovery: # 當config server注冊到eureka時配置
enabled: true # 開啟從注冊中心查找服務功能
service-id: config-center # config server 在注冊中心的注冊名
至此,在Spring Cloud中使用Config配置中心,以及配合bus實現自動刷新已經全部完成。如需參考完整代碼,可以訪問https://github.com/ithushuai/cloud
1.git倉庫中的配置文件的名稱要與客戶端服務的application name對應
2.bootstrap.yml先於application.yml加載,因此拉取配置文件功能相關的配置要在bootstrap.yml中配置,例如config的設置,Eureka的相關配置,application name的配置等等