1. 程式人生 > >Spring Cloud(四)配置中心Config

Spring Cloud(四)配置中心Config

在分散式系統中,由於服務數量巨多,為了方便服務配置檔案統一管理,實時更新,所以需要分散式配置中心元件。在Spring Cloud中,有分散式配置中心元件spring cloud config ,它支援配置服務放在配置服務的記憶體中(即本地),也支援放在遠端Git倉庫以及資料庫中。在spring cloud config 元件中,分兩個角色,一是config server,二是config client。

在本文中,我們將分別構建基於Git、基於Mysql 資料庫儲存的分散式配置中心,並對客戶端進行改造,並讓其能夠從配置中心獲取配置資訊並繫結到程式碼中的整個過程。

基於GIT儲存

理解配置中心搜尋路徑

配置資訊的URL與配置檔案的對映關係如下:

- /{application}/{profile}[/{label}]
- /{application}-{profile}.yml
- /{label}/{application}-{profile}.yml
- /{application}-{profile}.properties
- /{label}/{application}-{profile}.properties

準備配置倉庫

在這裡,我在 Gitee 上建立了一個公開的 repo, config-repo-demo 裡面建立 mz-eureka-client-one 的資料夾,存放 mz-eureka-client-one

專案的配置檔案。地址:https://gitee.com/mrzhouy/config-repo-demo

構建 Server 端

建立一個 SpringBoot 的基礎專案 mz-config-server-git ,同時引入 config 的依賴 spring-cloud-config-server

POM 檔案如下:

 <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId
>
spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency> </dependencies>

建立專案配置檔案 bootstarp.yml , 配置如下:

eureka:
    client:
        serviceUrl:
            defaultZone: http://localhost:1001/eureka/
server:
    port: 1003
spring:
    application:
        name: mz-config-server-git
    cloud:
        config:
            server:
                git:
                    searchPaths: '{application}'
                    uri: https://gitee.com/mrzhouy/config-repo-demo

spring clour config git 屬性解釋:

uri: 倉庫地址
username:訪問賬號(私庫才需要輸入)
password:賬號密碼(私庫才需要輸入)
searchPaths:git倉庫子目錄

當然,在某些時候我們希望對不同的子專案訪問不同的git倉目錄,因此我們可以在使用如下配置:

searchPaths: '{application}'

注:config 客戶端在沒有 spring.cloud.config.name屬性的時候,服務端{application} 獲取的是客戶端 
spring.application.name的值,否則,獲取的是 spring.cloud.config.name的值。 
1)、當沒有spring.cloud.config.name時,客戶端獲取的是spring.application.name 所對應的git庫中的檔案,並且只能獲取一個檔案, 
2)、當一個專案中有需求要獲取多個檔案時,就需要用到spring.cloud.config.name這個屬性,以逗號分割

開啟服務

啟動類上新增 @EnableConfigServer 註解開啟 config server 服務。程式碼如下:

@EnableDiscoveryClient
@EnableConfigServer
@SpringBootApplication
public class ConfigServerApplication  extends SpringBootServletInitializer {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class, args);
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(ConfigServerApplication.class);
    }
}

升級客戶端(client)

客戶端這裡,我們直接在之前的 mz-eureka-client-one 專案中進行升級。

新增config依賴:

<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-config</artifactId>
</dependency>

修改配置檔案 bootstarp.yml 新增 config 配置:

spring:
    cloud:
        config:
            discovery:
                enabled: true
                service-id: mz-config-server-git
                #uri: http://localhost:8888/
            label: master
            profile: test
    
#注:如果config server 沒有注入到註冊中心,我們在這裡可以通過 uri 來指定配置中心地址。但是生產、測試、開發環境中,我的配置中心是多個,因此我是將配置中心註冊到了註冊中心,通過 service-id 來訪問註冊中心的。

改造 HelloController:

@RestController
public class HelloController {
    @Value("${server.port}")
    private String serverPort;
    @Value("${info.message}")
    private String infoMessage;
    @RequestMapping("hi")
    public String sayHi() {
        return "Hi Spring Cloud, running in port :" + serverPort + "     info.message is : " + infoMessage;
    }
}

至此,配置中心已經構建完成,按順序啟動 註冊中心、配置中心 、客戶端。 呼叫 http://localhost:2001/hi ,我們可以看到通過配置中心拿到的 info.message 這個值。

基於 MySql 儲存

前面我們已經完成了基於 GIT 儲存的配置中心,其實升級為mysql儲存很簡單。只需要修改 POM 依賴(引入資料庫依賴),以及 bootstarp.yml 屬性檔案即可。在這裡,我們建立新的專案 mz-config-server-mysql ,POM 檔案如下:

<parent>
        <artifactId>SpringCloud-Learning</artifactId>
        <groupId>com.mz</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>mz-config-server-mysql</artifactId>
    <description>Spring Cloud 配置中心——MySql</description>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
        <!-- 引入資料庫依賴-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.21</version>
        </dependency>
    </dependencies>

修改 bootstarp.yml

指定 spring.profiles.active = jdbc,然後增加 jdbc配置

eureka:
    client:
        serviceUrl:
            defaultZone: http://localhost:1001/eureka/
server:
    port: 1003
spring:
    application:
        name: mz-config-server-mysql
    profiles:
        active: jdbc
    cloud:
        config:
            label: master
            server:
                jdbc:
                    sql: SELECT `KEY`, `VALUE` from PROPERTIES where APPLICATION=? and PROFILE=? and LABEL=?
    datasource:
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/db_microserver_config
        username: root
        password: TW123

建立資料庫的sql 檔案在專案中:ConfigMySql.sql

至此,修改完成,按順序啟動 註冊中心、配置中心 、客戶端(記得修改配置中心的serverId哦)。 呼叫 http://localhost:2001/hi ,我們可以看到通過配置中心拿到的 info.message 這個值。

Refresh

上面我們成功的完成了配置中心,但是這個時候就產生了疑問,client是在專案啟動的時候就請求了配置中心,獲取到了配置,如圖: 在這裡插入圖片描述

那再我們修改完配置中心的配置後,如何重新整理配置呢。如果需要重啟專案的話,配置中心就會顯得比較雞肋。

別急,spring cloud 當然為我們提供了重新整理的辦法。僅修改客戶端即 mz-eureka-client-one 專案,就可以實現 refresh 的功能。

新增依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

增加了spring-boot-starter-actuator包,spring-boot-starter-actuator是一套監控的功能,可以監控程式在執行時狀態,其中就包括/actuator/refresh的功能。

開啟更新機制

需要給載入變數的類上面載入@RefreshScope,在客戶端執行/actuator/refresh的時候就會更新此類下面的變數值。

@RestController
@RefreshScope
public class HelloController {
    @Value("${server.port}")
    private String serverPort;
    @Value("${info.message}")
    private String infoMessage;
    @RequestMapping("hi")
    public String sayHi() {
        return "Hi Spring Cloud, running in port :" + serverPort + "     info.message is : " + infoMessage;
    }
}

配置

Spring Boot 1.5.X 以上預設開通了安全認證,所以要在配置檔案 application.yml 中新增以下配置以將/actuator/refresh這個 Endpoint 暴露出來

management:
  endpoints:
    web:
      exposure:
        include: refresh

測試

改造完之後,我們重啟 mz-eureka-consumer-one,我們以 POST 請求的方式來訪問 http://localhost:2001/actuator/refresh 就會更新配置檔案至最新版本。

測試流程:

  1. 訪問 http://localhost:2001/hi 返回Hi Spring Cloud, running in port :2001 info.message is : i am config by jdbc
  2. 我將 Git 上對應配置檔案裡的值改為i am config by jdbc update
  3. 傳送 Post 請求到 http://localhost:2001/actuator/refresh
  4. 訪問 http://localhost:2001/hi 返回Hi Spring Cloud, running in port :2001 info.message is : i am config by jdbc update

不過,每次手動重新整理客戶端也很麻煩,有沒有什麼辦法只要提交程式碼就自動呼叫客戶端來更新呢,Github 的 Webhook 是一個辦法。

Webhook

Webhook 是當某個事件發生時,通過傳送 HTTP POST 請求的方式來通知資訊接收方。Webhook 來監測你在 Github.com 上的各種事件,最常見的莫過於 push 事件。如果你設定了一個監測 push 事件的 Webhook,那麼每當你的這個專案有了任何提交,這個 Webhook 都會被觸發,這時 Github 就會發送一個 HTTP POST 請求到你配置好的地址。

如此一來,你就可以通過這種方式去自動完成一些重複性工作,比如,你可以用 Webhook 來自動觸發一些持續整合(CI)工具的運作,比如 Travis CI;又或者是通過 Webhook 去部署你的線上伺服器。下圖就是 Github 上面的 Webhook 配置。 在這裡插入圖片描述

  • Payload URL :觸發後回撥的 URL
  • Content type :資料格式,兩種一般使用 json
  • Secret :用作給 POST 的 body 加密的字串。採用 HMAC 演算法
  • events :觸發的事件列表。
events 事件型別 描述
push 倉庫有 push 時觸發。預設事件
create 當有分支或標籤被建立時觸發
delete 當有分支或標籤被刪除時觸發

這樣我們就可以利用 hook 的機制去觸發客戶端的更新,但是當客戶端越來越多的時候,hook 機制也不夠優雅了,另外每次增加客戶端都需要改動 hook 也是不現實的。其實,Spring Cloud 給了我們更好解決方案——Spring Cloud Bus。後續我們將繼續學習如何通過 Spring Cloud Bus 來實現以訊息匯流排的方式進行通知配置資訊的變化,完成叢集上的自動化更新。

專案地址