Spring Cloud 之配置服務器(下)配置刷新

學習目標

本文所講內容為上一文的后續(xù),我們在上一文中學習了什么是 Spring Cloud 的配置服務器;如何使用兩種方式搭建 Spring Cloud Config Server 以及客戶端如何連接配置服務器。本文將以問題解答的形式一步步講解如何刷新配置,所用示例項目仍為上文所用代碼:

  • spring-cloud-chapter-3-config-server 端口:9090
  • spring-cloud-chapter-3-config-client 端口:8080

動態(tài)配置屬性 Bean

當我們的服務發(fā)布到了服務器上后,我們想要修改配置文件中的某些配置,我們該怎么辦呢?有些小伙伴就會說:“把服務停掉,修改配置文件后重新啟動不就解決了”。的確,這是一種解決辦法,但是并不是一種好的解決辦法,停掉服務器會對用戶產生很大的影響,尤其是在單體應用中,你把服務器停掉,別人就無法訪問,客戶就抓狂了,你的客服同事也會恨死你。那么這里我們就講解一下如何動態(tài)配置,讓服務正常運行的同時,修改配置信息。
1)在 spring-cloud-chapter-3-config-client 項目中定義配置屬性 Bean User,此處使用了 @ConfigurationProperties(prefix = "xxx") 注解。

package top.alanshelby.springcloudchapter3configclient.domain;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "as.user")
public class User {

    private Long id;

    private String name;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

2)創(chuàng)建 UserController,并使用構造器的方式注入 User 對象,使用 @EnableConfigurationProperties(User.class) 注解。

package top.alanshelby.springcloudchapter3configclient.web.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import top.alanshelby.springcloudchapter3configclient.domain.User;

@RestController
@EnableConfigurationProperties(User.class)
public class UserController {

    private final User user;

    @Autowired
    public UserController(User user) {
        this.user = user;
    }

    @GetMapping("/user")
    public User user() {
        return user;
    }
}

3)將 User 關聯(lián)配置項,在 application.properties 中進行配置

as.user.id = 1
as.user.name = AlanShelby

通過瀏覽器訪問:http://localhost:8080/env/as.user.*

{
    "as.user.name":"AlanShelby",
    "as.user.id":"1"
}

可以看到我們的配置已經(jīng)生效了,準備工作一切就緒,那么我們應該如何動態(tài)修改配置信息呢?這里我們需要借助 PostMan 工具來進行修改。

4)配置完成后,可以使用 PostMan 發(fā)送 POST 請求可動態(tài)修改參數(shù)信息

修改完成后,重新通過瀏覽器訪問:http://localhost:8080/env/as.user.*,可以看到配置信息已經(jīng)修改過來了,這樣就實現(xiàn)了在不重啟服務的前提下修改配置信息。

{
    "as.user.name":"spring-cloud",
    "as.user.id":"2"
}

說到這,不知道小伙伴們有沒有什么疑問。我們所講的內容為微服務方面的知識,也就是說不可能僅僅只有一個服務發(fā)布,如果在整個微服務項目中有幾十個或者幾百個服務實例,難道我們要手動挨個進行修改嗎?不存在的,那樣我們程序猿們早就撂挑子不干了,所以我們要想一個辦法,能夠調整所有機器的配置,那我們應該如何做呢?接下來,我們來一起解決這個問題。


問題:如果需要調整所有機器的配置應該如何操做?

解決這個問題前,我們要先搞明白一些事情,在上一文中我們講了如何搭建 Spring Cloud Config Server,我們講解了兩種方式,這里我們要了解的是配置客戶端應用所關聯(lián)的分布式配置信息,優(yōu)先于傳統(tǒng)的配置信息,如 application.properties (application.yml)或者是 bootstrap.properties (bootstrap.yml),由此可知,要解決這個問題,我們可以對配置服務器配置信息進行調整(blogstemp-prod.properties)。
啟動 spring-cloud-chapter-3-config-server 項目,服務端啟動完畢后重啟 spring-cloud-chapter-3-config-client 項目

注意:blogstemp-prod.properties 為上文中基于遠程 git 倉庫使用的配置文件,這里依舊使用它作為例子。

1)在 blogstemp-prod.properties 文件中添加如下信息:

as.user.id = 1000
as.user.name = AlanShelbyTest

修改完成后,將代碼提交到 GitHub,訪問:http://localhost:9090/blogstemp/prod,即可發(fā)現(xiàn)服務端配置信息就改過來了。

但是當我們訪問客戶端時:http://localhost:8080/env,就會發(fā)現(xiàn),客戶端并沒有及時把服務端的配置信息同步過來,那這個應該如何解決呢?

這里我們可以使用 Spring Cloud 給我們提供的 refresh 端點來進行刷新操作,依舊使用 PostMan 進行操作:

請求完成后,會返回給我們修改的配置 key:

[
  "as.user.id",
  "config.client.version",
  "as.user.name"
]

重新訪問 http://localhost:8080/env,就會發(fā)現(xiàn)我們剛剛修改的配置已經(jīng)同步過來了。

chapter3.2-4.png

這樣修改的分布式配置信息就可以應用于所有服務實例了,是不是一舉多得。
客戶端調整所有機器的配置的問題解決了,那么新的問題又出現(xiàn)了。我們剛剛使用了 Spring Cloud 給我們提供的 refresh 端點手動為客戶端刷新了遠程配置信息,這樣很不方便,每次修改完信息后,都要有專門的人員來進行刷新操作,十分不友好,那么我們如何讓服務端更新配置信息后,客戶端進行感知后自動刷新呢?接下來我們就來解決一下這個問題。


問題:如果服務端更新了,客戶端如何感知?

從上面我們已經(jīng)知道了可以使用 Spring Cloud 給我們提供的 refresh 端點手動進行刷新操作,客戶端感知說白了就是客戶端定時刷新,所以我們使用一個簡易的定時任務就可以解決這個問題,這種方式只是一種解決辦法,較為簡單、方便,還有很多其他的解決方式(如官方文檔中提供的整合 Spring Cloud Bus 和 spring-cloud-config-monitor),這里只是提供解決思路,讀者可自行斟酌使用。

1)使用構造器注入的方式將 ContextRefresher 進行注入,使用定時任務每5秒(根據(jù)需求自行設定)對上下文進行一次刷新,這里使用了 contextRefresher.refresh() 進行刷新。

package top.alanshelby.springcloudchapter3configclient;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.context.refresh.ContextRefresher;
import org.springframework.scheduling.annotation.Scheduled;

import java.util.Set;

@SpringBootApplication
public class SpringCloudChapter3ConfigClientApplication {

    private final ContextRefresher contextRefresher;

    // 使用構造器注入的方式將 contextRefresher 進行注入
    @Autowired
    public SpringCloudChapter3ConfigClientApplication(ContextRefresher contextRefresher) {
        this.contextRefresher = contextRefresher;
    }

    @Scheduled(fixedRate = 5000L)
    public void update() {
        Set<String> keys = contextRefresher.refresh();

        if (!keys.isEmpty()) {
            System.out.println("本次更新的配置項:" + keys);
        }
    }

    public static void main(String[] args) {
        SpringApplication.run(SpringCloudChapter3ConfigClientApplication.class, args);
    }
}

2)修改 blogstemp-prod.properties 配置文件,并提交到遠程 GitHub 倉庫

as.user.id = 1001
as.user.name = Shelby

3)查看日志信息,可以看到輸入如下信息,表明上下文的刷新操作完成:

本次更新的配置項:[as.user.id, config.client.version, as.user.name]

至此,關于Spring Cloud Config Server(配置服務器)所有內容就講解完了,這是我的理解,各位看官如果有不同見解或文章中有錯誤,請不吝指正。
所用代碼碼云地址:https://gitee.com/AlanShelby/spring-cloud-chapter
知乎專欄地址:https://zhuanlan.zhihu.com/c_200981602
個人微信公眾號:AlanShelby(多多關注,感謝~)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容