偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

搞懂Spring Cloud Config配置信息自動更新原理

開發(fā) 前端
Spring Cloud Bus 是 Spring Cloud 中用于實現(xiàn)消息總線的專用組件,它集成了 RabbitMQ、Kafka 等主流消息中間件。

我們知道 Spring Cloud Config 是 Spring Cloud 提供的配置中心實現(xiàn)工具,我們可以通過它把配置信息存放在 Git 等第三方配置倉庫中。每當(dāng) Spring Cloud Config 客戶端啟動時,就會發(fā)送 HTTP 請求到服務(wù)器端獲取配置信息,這點(diǎn)比較好理解。但事實上,在 Git 中更改了配置信息之后,客戶端并不會主動再次請求最新配置,而是使用緩存到本地的原有配置信息。如圖 1。

圖 1 配置信息自動更新問題圖 1 配置信息自動更新問題

那么問題就來了,在這種情況下, Spring Cloud Config 是如何實時獲取到更改后的配置呢?這就是今天我們要討論的內(nèi)容。通過理解 Spring Cloud Config 配置信息自動更新的執(zhí)行過程,有助于我們深入把握框架的底層原理。

在對底層原理進(jìn)行詳細(xì)展開之前,我們先來給出 Spring Cloud Config 應(yīng)對這一問題的具體做法。事實上,Spring Cloud Config 能夠做到配置信息的自動更新,是依賴于 Spring Cloud 中的另一個組件,即 Spring Cloud Bus。

Spring Cloud Bus 是 Spring Cloud 中用于實現(xiàn)消息總線的專用組件,它集成了 RabbitMQ、Kafka 等主流消息中間件。當(dāng)我們在 Spring Cloud Config 服務(wù)器端代碼工程的類路徑中添加 Spring Cloud Bus 的引用并啟動應(yīng)用程序之后,Spring Boot Actuator 就為我們提供了/actuator/bus-refresh 端點(diǎn), 通過訪問該端點(diǎn)就可以達(dá)到對客戶端所有服務(wù)實例的配置信息進(jìn)行自動更新的效果。在這種方案中,服務(wù)端會主動通知所有客戶端進(jìn)行配置信息的更新,這樣我們就無需關(guān)注各個客戶端,而只對服務(wù)端進(jìn)行操作即可。

是不是聽起來有點(diǎn)神奇?整個實現(xiàn)過程我們至少要搞清楚三大問題,如圖 2 所示。

圖 2 實現(xiàn)配置信息自動更新的三個問題圖 2 實現(xiàn)配置信息自動更新的三個問題

針對這三個問題,接下來我們將結(jié)合源碼逐一展開討論。

問題一:如何自動調(diào)用服務(wù)器端所暴露的/actuator/bus-refresh 端點(diǎn)?

在現(xiàn)代軟件開發(fā)過程中,開放式平臺是一種常見的軟件服務(wù)形態(tài)。我們可以把 Spring Cloud Config Server 所提供的 HTTP 端點(diǎn)視為一種開放式的接口,以供 Git 等第三方工具進(jìn)行訪問和集成。

基于這種思想,我們可以把服務(wù)器端/actuator/bus-refresh 端點(diǎn)對外進(jìn)行暴露,然后第三方工具通過這個暴露的端點(diǎn)進(jìn)行集成。例如,在 Github 中就設(shè)計了一種 Webhook 機(jī)制,并提供了用戶界面供我們配置所需要集成的端點(diǎn)以及對應(yīng)的操作,操作方法如圖 3 所示。

圖 3 Github 的 Webhook 配置界面(來自 Github 官網(wǎng))圖 3 Github 的 Webhook 配置界面(來自 Github 官網(wǎng))

我們可以在上圖的 Payload URL 中設(shè)置/actuator/bus-refresh 端點(diǎn)地址。所謂的 Webhook,實際上就是一種回調(diào)。通過 Webhook,當(dāng)我們提交代碼時,Github 就會自動調(diào)用所配置的 HTTP 端點(diǎn)。也就是說,我們可以根據(jù)配置項信息的更新情況自動實現(xiàn)對/actuator/bus-refresh 端點(diǎn)的訪問?;?Github 的配置倉庫實現(xiàn)方案,我們可以得到如下圖所示的系統(tǒng)結(jié)構(gòu)圖。

圖 4 Github Webhook 機(jī)制執(zhí)行效果圖圖 4 Github Webhook 機(jī)制執(zhí)行效果圖

現(xiàn)在,配置信息一旦有更新,Spring Cloud Config Server 就能從 Github 中獲取最新的配置信息了。

問題二:客戶端如何得知服務(wù)器端的配置信息已經(jīng)更新?

接下來我們關(guān)注第二個問題,即客戶端如何得知服務(wù)器端的配置信息已經(jīng)更新?

我們首先需要明確,調(diào)用了/actuator/bus-refresh 端點(diǎn)之后,系統(tǒng)內(nèi)部會發(fā)生了什么。這里我們快速瀏覽 Spring Cloud Bus 中的代碼工程,發(fā)現(xiàn)存在一個 RefreshBusEndpoint 端點(diǎn)類,如下所示:

@Endpoint(id = "bus-refresh")
public class RefreshBusEndpoint extends AbstractBusEndpoint {
    @WriteOperation
    public void busRefreshWithDestination(@Selector String destination) {
        //發(fā)布 RefreshRemoteApplicationEvent 事件
        publish(new RefreshRemoteApplicationEvent(this, getInstanceId(), destination));
    }
    @WriteOperation
    public void busRefresh() {
        //發(fā)布 RefreshRemoteApplicationEvent 事件
        publish(new RefreshRemoteApplicationEvent(this, getInstanceId(), null));
    }
}

顯然,RefreshBusEndpoint 類對應(yīng)于我們前面訪問的/bus-refresh 端點(diǎn)。可以看到,Spring Cloud Bus 在這里做的事情僅僅只是發(fā)布了一個新的 RefreshRemoteApplicationEvent 事件。

既然發(fā)送了事件,我們就需要尋找該事件的監(jiān)聽者。我們在 Spring Cloud Bus 中找到了 RefreshRemoteApplicationEvent 事件的監(jiān)聽器 RefreshListener,如下所示:

public class RefreshListener implements ApplicationListener<RefreshRemoteApplicationEvent> {
    …
    @Override
    public void onApplicationEvent(RefreshRemoteApplicationEvent event) {
        //執(zhí)行配置屬性的刷新操作
        Set<String> keys = contextRefresher.refresh();
    }
}

從類的定義中不難看出該監(jiān)聽器就是用來處理 RefreshRemoteApplicationEvent 事件??梢钥吹?,在它的 onApplicationEvent 方法中同樣也是調(diào)用了 ContextRefresher 中的 refresh 方法進(jìn)行配置屬性的刷新。

請注意,RefreshRemoteApplicationEvent 是一個遠(yuǎn)程事件,將通過消息中間件進(jìn)行發(fā)送,并被 Spring Cloud Config 客戶端所監(jiān)聽,處理流程如下圖所示:

圖 5 基于 Spring Cloud Bus 的事件傳播機(jī)制圖 5 基于 Spring Cloud Bus 的事件傳播機(jī)制

問題三:客戶端如何實時獲取服務(wù)器端所更新的配置信息?

最后需要明確的第三個問題是,客戶端如何獲取服務(wù)器端所更新的配置信息,這就需要梳理 Spring Cloud Config Server 與注冊中心之間的關(guān)系。

我們知道配置中心作為整個微服務(wù)架構(gòu)運(yùn)行所需的基礎(chǔ)服務(wù),需要確保其可用性。因為配置服務(wù)本身也是一個獨(dú)立的微服務(wù),所以 Spring Cloud Config 實現(xiàn)高可用的方式很簡單。跟其他微服務(wù)一樣,它把自己注冊到注冊中心上,讓其他服務(wù)提供者或消費(fèi)者通過注冊中心進(jìn)行服務(wù)發(fā)現(xiàn)和獲取。

圖 6 Spring Cloud Config 與注冊中心之間的關(guān)系圖 6 Spring Cloud Config 與注冊中心之間的關(guān)系

顯然,在這種方式下,注冊中心的服務(wù)治理機(jī)制同時提供了服務(wù)器端的負(fù)載均衡和客戶端的配置功能,從而也就間接實現(xiàn)了高可用性。從另一個角度,我們也可以理解為,可以通過注冊中心獲取所有 Spring Cloud Config 客戶端服務(wù)的實例,從而在分布式環(huán)境下為獲取配置信息提供了一種簡便的手段。

Spring Cloud Config 提供了一個工具類 ConfigServerInstanceProvider 來完成與注冊中心之間的交互,代碼如下所示:

public class ConfigServerInstanceProvider {
   private final DiscoveryClient client;
   @Retryable(interceptor = "configServerRetryInterceptor")
   public List<ServiceInstance> getConfigServerInstances(String serviceId) {
       List<ServiceInstance> instances = this.client.getInstances(serviceId);
       if (instances.isEmpty()) {
           //拋出異常
       }
       return instances;
    }
}

在這里,我們看到了熟悉的 DiscoveryClient,DiscoveryClient 通過同樣熟悉的 getInstances 方法從注冊中心中獲取 Spring Cloud Config 服務(wù)器實例,如下所示:

List<ServiceInstance> instances = this.client.getInstances(serviceId);

ConfigServerInstanceProvider 的調(diào)用者是 DiscoveryClientConfigServiceBootstrapConfiguration?,F(xiàn)在我們來看這個 Spring Boot 自動配置類的定義,如下所示:

public class DiscoveryClientConfigServiceBootstrapConfiguration
        implements SmartApplicationListener {
    public void startup(ContextRefreshedEvent event) {
        refresh();
    }
}

可以看到,如果系統(tǒng)中生成了 ContextRefreshedEvent 事件就會觸發(fā)如下所示的 refresh 方法。

private void refresh() {
    try {
        ////獲取 Spring Cloud Config 客戶端服務(wù)實例
        String serviceId = this.config.getDiscovery().getServiceId();
        List<String> listOfUrls = new ArrayList<>();
        List<ServiceInstance> serviceInstances = this.instanceProvider.getConfigServerInstances(serviceId);
        //遍歷服務(wù)實例列表
        for (int i = 0; i < serviceInstances.size(); i++) {
            ServiceInstance server = serviceInstances.get(i);
            String url = getHomePage(server);
             //獲取配置路徑
            if (server.getMetadata().containsKey("configPath")) {
                String path = server.getMetadata().get("configPath");
                if (url.endsWith("/") && path.startsWith("/")) {
                    url = url.substring(0, url.length() - 1);
                }
                url = url + path;
            }
             //填充配置路徑
            listOfUrls.add(url);
        }
        String[] uri = new String[listOfUrls.size()];
        uri = listOfUrls.toArray(uri);
        this.config.setUri(uri);
    }
}

在上述 refresh 方法中,Spring Cloud Config 首先會獲取配置文件中配置項 spring.cloud.config.discovery.serviceId 所指定的服務(wù)實例 id,然后根據(jù) serviceId 從 ConfigServerInstanceProvider 中獲取注冊服務(wù)的實例對象集合 serviceInstances,最后循環(huán)遍歷 serviceInstances 來更新存儲在內(nèi)存中的配置屬性值。

至此,我們通過解答三個問題,引出了 Spring Cloud Config 中實現(xiàn)配置信息自動更新的三個步驟,并基于框架內(nèi)部一系列組件之間的交互過程剖析了底層實現(xiàn)原理。

總結(jié)

今天基于 Spring Cloud Config 框架剖析了實現(xiàn)配置信息自動更新的工作原理。拋出了三個與這個主題相關(guān)的核心問題,然后基于源碼對這些問題做了一一解答。

事實上,Spring Cloud Config 作為 Spring 自研的配置中心框架,其內(nèi)部大量使用了 Spring 現(xiàn)有的功能特性,比方說這節(jié)課中提到的 Spring 容器的事件發(fā)布和監(jiān)聽機(jī)制,又比方說 Spring Boot Acuator 中的端點(diǎn)機(jī)制以及 Spring Cloud Bus 所具備的消息通信總線機(jī)制。這點(diǎn)與我們學(xué)習(xí) Netflix 旗下的 Eureka、Zuul 等框架不同。我們需要首先對 Spring 容器相關(guān)的知識體系有足夠的了解,才能更好地理解 Spring Cloud Config 的設(shè)計和實現(xiàn)方式。

責(zé)任編輯:武曉燕 來源: 程序員技術(shù)充電站
相關(guān)推薦

2017-10-31 14:58:11

Spring Clou配置信息問題

2023-11-22 17:00:10

ElectronWeb

2015-03-30 14:15:55

自動更新Android

2015-09-15 15:25:36

更新配置Windows 10

2010-05-24 11:27:20

SVN配置自動更新WE

2021-11-08 22:24:04

Windows 10Windows微軟

2017-10-20 12:13:11

數(shù)據(jù)庫PostgreSQL時間戳

2016-07-12 10:09:13

OpenManage大

2010-01-08 13:20:52

ibmdwWeb

2025-02-10 00:14:00

2018-07-27 15:43:24

Spring Clou管理架構(gòu)

2023-09-12 13:12:23

服務(wù)器系統(tǒng)

2012-04-16 14:55:29

MacChrome

2025-02-27 00:10:19

2010-12-13 13:33:47

Windows 7驅(qū)動

2018-06-22 15:46:45

Spring Clou加密處理

2018-07-10 14:55:32

Git存儲配置

2021-04-20 10:15:34

Spring ClouZuul架構(gòu)

2017-01-12 21:02:29

Windows 10系統(tǒng)更新

2021-07-26 16:23:13

Windows 10Windows微軟
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號