日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
做一個簡易的配置中心,順帶還給整合到了SpringCloud

大家好,我是三友~~

為馬村等地區(qū)用戶提供了全套網(wǎng)頁設(shè)計制作服務(wù),及馬村網(wǎng)站建設(shè)行業(yè)解決方案。主營業(yè)務(wù)為網(wǎng)站設(shè)計、成都網(wǎng)站建設(shè)、馬村網(wǎng)站設(shè)計,以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會得到認(rèn)可,從而選擇與我們長期合作。這樣,我們也可以走得更遠(yuǎn)!

最近突然心血來潮(就是閑的)就想著擼一個簡單的配置中心,順便也照葫蘆畫瓢給整合到SpringCloud。

配置中心的概述

隨著歷史的車輪不斷的前進(jìn),技術(shù)不斷的進(jìn)步,單體架構(gòu)的系統(tǒng)都逐漸轉(zhuǎn)向微服務(wù)架構(gòu)。雖然微服務(wù)架構(gòu)有諸多優(yōu)點,但是隨著越來越多的服務(wù)實例的數(shù)量,配置的不斷增多,傳統(tǒng)的配置文件方式不能再繼續(xù)適用業(yè)務(wù)的發(fā)展,所以急需一種可以統(tǒng)一管理配置文件應(yīng)用,在此之下配置中心就誕生了。

所以配置中心就是用來統(tǒng)一管理各種服務(wù)配置的一個組件,本質(zhì)上就是一個web應(yīng)用。

配置中心的核心功能

一個配置中心的核心功能其實主要包括兩個:

  • 配置的存取
  • 配置變更的通知

配置的存取是配置中心不可缺失的功能,配置中心需要能夠?qū)⑴渲眠M(jìn)行保存,存在磁盤文件也好,又或是數(shù)據(jù)庫也罷,總之需要持久化,同時配置中心也得提供配置查詢的功能。

配置變化的通知也是一個很重要的功能,一旦配置中心的配置有變動的話,那么使用到這個配置的客戶端就需要知道這個配置有變動,從而可以做到相應(yīng)的變動的操作。

手?jǐn)]一個簡易的配置中心

上文分析了一個配置中心的核心功能,接下來就實現(xiàn)這兩個核心的功能。

一、文件工程整體分析

文件工程整體分為客戶端與服務(wù)端

  • 服務(wù)端:單獨部署的一個web應(yīng)用,端口是8888,提供了對于配置增刪改查的http接口
  • 客戶端(SDK):業(yè)務(wù)系統(tǒng)需要引用對應(yīng)的依賴,封裝了跟服務(wù)端交互的代碼

二、服務(wù)端實現(xiàn)詳解

1、配置文件的數(shù)據(jù)存儲模型ConfigFile

在配置中心存儲配置的時候,需要指明以下信息

public class ConfigFile {

private String fileId;

private String name;

private String extension;

private String content;

private Long lastUpdateTimestamp;

}

fileId: 文件的唯一id,由配置中心服務(wù)端在新增配置文件存儲的時候自動生成,全局唯一

name: 就是文件的名字,沒有什么要求,見名知意就行

extension: 文件后綴名,指的是該配置是什么類型的文件,比如是properties、yml等

content: 就是配置文件的內(nèi)容,不同的后綴名有不同的格式要求

lastUpdateTimestamp: 上一次文件更新的時間戳。當(dāng)文件存儲或者更新的時候,需要更新時間戳,這個字段是用來判斷文件是否有改動

2、文件存儲層ConfigFileStorage

對于文件存儲層,我提供了一個ConfigFileStorage接口,

public interface ConfigFileStorage {

void save(ConfigFile configFile);

void update(ConfigFile configFile);

void delete(String fileId);

ConfigFile selectByFileId(String fileId);

List selectAll();

}

這個接口提供了對于配置存儲的crud操作,目前我已經(jīng)實現(xiàn)了基于內(nèi)存和磁盤文件的存儲的代碼

可以在項目啟動的時候,在配置文件指定是基于磁盤文件存儲還是基于內(nèi)存存儲,默認(rèn)是基于磁盤文件存儲。

當(dāng)然,如果想把配置信息存儲到數(shù)據(jù)庫,只要新增一個存儲到數(shù)據(jù)的實現(xiàn)就行。

3、ConfigController

ConfigController提供了對于配置文件的crud的http接口

ConfigController是通過調(diào)用ConfigManager來完成配置文件的crud

4、ConfigManager

其實就是一個service層,就是簡單的參數(shù)封裝,最終是調(diào)用ConfigFileStorage存儲層的實現(xiàn)來完成配置的存儲功能。

這樣配置中心的配的存取的功能就實現(xiàn)了。

所以,服務(wù)端還是比較簡單的。其實就是跟平時寫的業(yè)務(wù)系統(tǒng)的crud沒什么區(qū)別,就是將數(shù)據(jù)庫存儲替換成了磁盤文件的存儲。

至于前面說的配置文件變更通知的功能,我是基于客戶端來實現(xiàn)的。

三、客戶端的實現(xiàn)

客戶端工程代碼如下

1、ConfigFileChangedListener

ConfigFileChangedListener

配置變動的監(jiān)聽器,當(dāng)客戶端對某個配置監(jiān)聽的時候,如果這個配置的內(nèi)容有變化的話,客戶端就會回調(diào)這個監(jiān)聽器,傳入最新的配置

2、ConfigService

封裝了客戶端的核心功能,可以添加對某個文件的監(jiān)聽器和獲取某個文件的配置內(nèi)容。

使用示例:

// 創(chuàng)建一個ConfigService,傳入配置中心服務(wù)端的地址
ConfigService configService = new ConfigService("localhost:8888");

// 從服務(wù)端獲取配置文件的內(nèi)容,文件的id是新增配置文件時候自動生成
ConfigFile config = configService.getConfig("69af6110-31e4-4cb4-8c03-8687cf012b77");

// 對某個配置文件進(jìn)行監(jiān)聽
configService.addListener("69af6110-31e4-4cb4-8c03-8687cf012b77", new ConfigFileChangedListener() {
@Override
public void onFileChanged(ConfigFile configFile){
System.out.printf("fileId=%s配置文件有變動,最新內(nèi)容為:%s%n", configFile.getFileId(), configFile.getContent());
}
});

這里說一下配置變更通知的實現(xiàn)原理。

首先對于客戶端來說,要想知道哪個配置文件進(jìn)行了改動,有兩種方式

第一種是通過push的方式來實現(xiàn)。當(dāng)配置文件發(fā)生變動的時候,服務(wù)端主動將變動的配置文件push給客戶端。這種方式實現(xiàn)起來比較麻煩,一方面是服務(wù)端還得存儲客戶端的服務(wù)的信息,因為服務(wù)端得知道push到哪臺服務(wù)器上;另一方面,客戶端需要提供一個接口來接收服務(wù)端push的請求,所以這種方式整體實現(xiàn)起來比較麻煩。但是這種push方式時實性比較好,一旦配置文件有變動,第一時間客戶端就能夠知道配置有變動。

第二種方式就是基于pull模式來實現(xiàn)??蛻舳硕〞r主動去服務(wù)端拉取配置文件,判斷文件內(nèi)容是否有變動,一旦有變動就進(jìn)行監(jiān)聽器的回調(diào)。這種實現(xiàn)相比push來說簡單不少,因為服務(wù)端不需要關(guān)心客戶端的信息,所有的操作都由客戶端來完成。但是這個定時的時間間隔不好控制,太長可能會導(dǎo)致時實性差,太短會導(dǎo)致可能無效請求過多,因為配置壓根可能沒有變化。

但是這里我選擇了第二種方式,因為實現(xiàn)起來簡單。。

變動通知代碼實現(xiàn)

到這,一個簡單的配置中心的服務(wù)端的和客戶端就完成了,這里畫張圖來總結(jié)一下配置中心的核心原理。

接下來就把這個簡易的配置中心整合到SpringCloud中。

SpringCloud配置中心的原理

1、項目啟動是如何從配置中心加載數(shù)據(jù)的?

在SpringCloud環(huán)境下,當(dāng)項目啟動的時候,在SpringBoot應(yīng)用容器創(chuàng)建之前,會先創(chuàng)建一個容器,這個容器非常重要,這個容器是用來跟配置中心交互,拉取配置的。

這個容器在啟動的時候會干兩件事:

  • 加載bootstrap配置文件,這就是為什么配置中心的配置信息需要寫在bootstrap配置文件的重要原因
  • 加載所有spring.factories文件中的鍵為org.springframework.cloud.bootstrap.BootstrapConfiguration對應(yīng)的配置類,將這些配置類注入到這個容器中,注意這里是不會加載@EnbaleAutoConfiguration自動裝配的類

當(dāng)這兩件事都做好之后,會從這個容器中獲取到所有的PropertySourceLocator這個接口的實現(xiàn)類對象,依次調(diào)用locate方法。

PropertySourceLocator

這個類很重要,先來看看注釋

Strategy for locating (possibly remote) property sources for the Environment. Implementations should not fail unless they intend to prevent the application from starting.

扔到有道翻譯如下:

為環(huán)境定位(可能是遠(yuǎn)程)屬性源的策略。實現(xiàn)不應(yīng)該失敗,除非它們打算阻止應(yīng)用程序啟動。

說的簡單點就是用來定位到(也就是獲取的意思)項目啟動所需要的屬性信息。同時要注意到括號內(nèi)的 可能是遠(yuǎn)程 告訴我們一個很重要的信息,那就是獲取的配置信息不僅僅可以存在本地,而且還可以存在遠(yuǎn)程。

遠(yuǎn)程?作者這里就差直接告訴你可以從配置中心獲取了。。

所以從這個注釋就可以發(fā)現(xiàn),原來PropertySourceLocator就是起到在SpringCloud環(huán)境下從配置中心獲取配置的作用。

PropertySourceLocator是一個接口,所以只要不同的配置中心實現(xiàn)這個接口,那么不同的配置中心就可以整合到了SpringCloud,從而實現(xiàn)從配置中心加載配置屬性到Spring環(huán)境中了。

2、如何實現(xiàn)注入到Bean中的屬性動態(tài)刷新?

上面講了在項目啟動的時候SpringCloud是如何從配置中心加載數(shù)據(jù)的,主要是通過新建一個容器,加載bootstrap配置文件和一些配置類,最后會調(diào)用PropertySourceLocator來從配置中心獲取到配置信息。

那么在SpringCloud環(huán)境下,是如何實現(xiàn)注入到Bean中的屬性動態(tài)刷新的呢?

舉個例子

UserService

當(dāng)在類上加一個@RefreshScope注解之后,那么當(dāng)配置中心sanyou.username的屬性有變化的時候,那么此時注入的username也會跟著變化。

這種變化是如何實現(xiàn)的呢?

SpringCloud中規(guī)定,當(dāng)配置中心客戶端一旦感知到服務(wù)端的某個配置有變化的時候,需要發(fā)布一個RefreshEvent事件來告訴SpringCloud配置有變動。

在SpringCloud中RefreshEventListener類會去監(jiān)聽這個事件,一旦監(jiān)聽到這個事件,就會進(jìn)行兩步操作來刷新注入到對象的屬性。

RefreshEventListener

  • 從配置中心再次拉取屬性值,而這個拉取的代碼邏輯跟項目啟動時拉取的屬性值核心邏輯幾乎是一樣的,也是創(chuàng)建一個新的spring容器,加載配置文件和配置類,最后通過PropertySourceLocator獲取屬性,這一部分核心的代碼邏輯是復(fù)用的。
  • 有了最新的屬性之后,就開始刷新對象的屬性。

刷新的邏輯實現(xiàn)的非常的巧妙,可不是你以為的簡單地將新的屬性重新注入對象中,而是通過動態(tài)代理的方式來實現(xiàn)的。

對于在類上加了@RefreshScope注解的Bean,Spring在生成這個Bean的時候,會進(jìn)行動態(tài)代理。

這里我們就上面舉個UserService例子來分析,在生成UserService有兩步操作

  • 生成一個UserService對象,將從配置中心拉到的配置sanyou.username注入給UserService對象
  • 由于加了@RefreshScope,會給上一步驟生成的UserService對象進(jìn)行代理,生成一個代理對象

最后真正暴露出去供我們使用的其實是就是這個代理對象,如圖所示:

由于暴露出去的是一個代理對象,所以當(dāng)調(diào)用getUsername方法的時候,其實是調(diào)用UserService的代理對象的getUsername方法,從而就會找到UserService,調(diào)用UserService的getUsername獲取到username的屬性值。

當(dāng)配置中心的配置有變動刷新屬性的時候,Spring會把UserService這個對象(非代理對象)給銷毀,重新創(chuàng)建一個UserService對象,注入最新的屬性值。

當(dāng)再次通過UserService代理對象獲取username屬性的時候,就會找最新創(chuàng)建的那個UserService對象,此時就能獲取到最新的屬性值。

配置每刷新一次,UserService對象就會先銷毀再重新創(chuàng)建,但是暴露出去的UserService代理對象一直不會變。

這樣,對于使用者來說,好像是UserService對象的屬性自動刷新了,其實本質(zhì)上是UserService代理對象最終找的UserService對象發(fā)生了變化。

到這應(yīng)該就知道為什么加了@RefreshScope的對象能夠?qū)崿F(xiàn)配置的自動刷新了,其實依靠的是動態(tài)代理完成的。

3、源碼執(zhí)行流程圖

由于上面并沒有涉及整體執(zhí)行流程的源碼分析,所以我特地結(jié)合源碼畫了兩張源碼的執(zhí)行流程圖,有興趣的小伙伴可以對照著圖翻一翻具體的源碼。

3.1啟動時加載配置流程

最終從配置中心獲取到的屬性會放在項目啟動時創(chuàng)建的 Environment 對象里面。

3.2配置刷新源碼流程

這個圖新增了對于加了@ConfigurationProperties數(shù)據(jù)綁定的對象原理的分析。

整合SpringCloud和測試

一、整合SpringCloud

1、ConfigCenterProperties

配置中心的配置信息,這里需要配置配置中心服務(wù)端的地址和使用的配置文件的id。當(dāng)然這部分信息需要寫在bootstrap配置文件中,前面也說過具體的原因。

2、ConfigCenterPropertySourceLocator

上面分析知道,項目啟動和刷新的時候,SpringCloud是通過PropertySourceLocator的實現(xiàn)從配置中心加載配置信息,所以這里就得實現(xiàn)一下

核心的邏輯就是根據(jù)所配置的文件的id,從配置中心拉取配置信息,然后解析配置。

3、ConfigContextRefresher

這個是用來注冊文件變動的監(jiān)聽器,來刷新文件的信息的。

因為上面提到,當(dāng)配置發(fā)生變化的時候,需要發(fā)布一個RefreshEvent事件來觸發(fā)刷新配置的功能。

核心的邏輯就是當(dāng)項目啟動的時候,對所使用的配置文件進(jìn)行注冊一個監(jiān)聽器,監(jiān)聽器的實現(xiàn)就是當(dāng)發(fā)生配置改動的時候,就發(fā)布一個RefreshEvent事件。

4、兩個配置類

4.1 ConfigCenterBootstrapConfiguration

配置了ConfigCenterPropertySourceLocator、ConfigCenterProperties、ConfigService

4.2 ConfigCenterAutoConfiguration

配置了ConfigContextRefresher、ConfigCenterProperties、ConfigService

最后需要將兩個配置類在spring.factories配置一下。

這里有個需要注意,前面說過,SpringCloud會創(chuàng)建新的容器來加載配置,而這個容器只會加載spring.factories文件中鍵為@BootstrapConfiguration注解的配置類,所以需要將ConfigCenterBootstrapConfiguration跟BootstrapConfiguration配對,因為ConfigCenterBootstrapConfiguration配置了ConfigCenterPropertySourceLocator。

好了,到這里真的就完成了對SpringCloud整合了。

二、測試

1、新增一個配置文件

啟動配置中心的server端,然后打開ApiPost,新增一個配置文件

新增文件類型為properties一個配置,內(nèi)容為sanyou.username=sanyou鍵值對,當(dāng)然可以寫很多鍵值對,我這里就寫了一個,新增成功之后,返回了文件的id:79765c73-c1ef-4ea2-ba77-5d27a64c4685

2、測試客戶端

這里我為了方便,就把測試代碼跟客戶端寫在同一個服務(wù)了,正常情況肯定是把跟SpringCloud代碼打成一個依賴引到項目中。

在bootstrap.yml文件中配置配置中心的相關(guān)信息

  • 配置中心服務(wù)端的地址是:localhost:8888
  • 使用的配置文件的id是剛才創(chuàng)建的:79765c73-c1ef-4ea2-ba77-5d27a64c4685

測試Controller

提供一個接口,注入上面提到的UserService

啟動項目,調(diào)用接口

從斷這里可以看出,實際注入的是一個UserService代理對象,并且最終找的是com.sanyou.configcenter.test.UserService@3a1e4fd3這個UserService對象

此時這次調(diào)用的返回值就是:sanyou

接下來測試一下自動刷新屬性的功能

現(xiàn)在修改一下配置中心的sanyou.username為sanyou666

靜靜等待5秒鐘。。

此時控制臺打印出 Refresh keys changed: [sanyou.username] ,也就是sanyou.username屬性變了

此時再次獲取username

可以看出,UserService代理對象沒變,但是UserService對象已經(jīng)變成了com.sanyou.configcenter.test.UserService@4237b3cd

此時獲取到的username就已經(jīng)變成了sanyou666

所以,到這里就成功將我們自己寫的那個簡易版的配置中心整合到了SpringCloud中了。

不足和改進(jìn)

雖然我們這里的配置中心有了配置中心基本的功能,但是其實還有很多的不足和可以改進(jìn)的地方。

1、配置變更推送問題

問題前面也說過,在判斷配置是否變更的時候,這里是每隔5s從服務(wù)端獲取一次,這里就會可能5s之后才能感知到配置有變化,達(dá)不到真正時實的效果,并且由于這里是由客戶端根據(jù)來判斷,會導(dǎo)致無效的請求過多,因為可能配置壓根沒有變化,但是還是每隔5s獲取一次配置信息,白白浪費資源

解決這個問題可以換成上面提到的push方式來做,或者將輪詢方式改成長輪詢的方式實現(xiàn)也是可以的,如果不清楚push、輪詢、長輪詢的,可以翻一下RocketMQ的push消費方式實現(xiàn)的太聰明了這篇文章。

2、高可用問題

這里服務(wù)端的實例只有一個,不支持集群的方式,就會有單點故障的問題,不支持高可用。在實際項目中,肯定要支持集群的方式,保證即使有服務(wù)實例掛了,整個集群仍然可以繼續(xù)對外提供服務(wù),比如nacos就支持集群的方式,并且可以自由選擇是使用AP模式還是CP模式。

3、通信協(xié)議和序列化協(xié)議

對于通信協(xié)議,這里為了方便,我選擇了客戶端和服務(wù)端的通信方式是基于http協(xié)議的,當(dāng)然也可以自定義協(xié)議,或者使用其它的協(xié)議,比如gRPC協(xié)議。其實在nacos2.x的版本中,nacos開始全面擁抱gRPC協(xié)議了。

至于序列化協(xié)議,這里選擇了json協(xié)議,因為很簡單、常見、使用范圍廣、跨語言,當(dāng)然也可以選擇其它的,比如hessian序列化協(xié)議等等。

4、多租戶隔離

一個合格的配置中心需要能支持不同應(yīng)用的隔離,還有同一個應(yīng)用不同環(huán)境的隔離,這里就圖省事,直接就是有一個文件id來表示,雖然也可以做到隔離(不同系統(tǒng)用不同的文件id),但是這種方式比較low。像nacos會自動根據(jù)配置的名稱和后綴名之類的,生成文件id(dataId),同時還有分組的概念,其實就是為了做到隔離的效果。

5、鑒權(quán)

鑒權(quán)是一個系統(tǒng)比較常見的東西,這里就不做過多贅述

6、控制頁面

上面所有對于配置的crud都是基于ApiPost來的,但是實際怎么也得通過一個頁面來操作吧,至于這里我為啥不自己寫個頁面,給你個眼神自己體會~~

最后,本文代碼地址:https://github.com/sanyou3/sanyou-config-center


文章標(biāo)題:做一個簡易的配置中心,順帶還給整合到了SpringCloud
路徑分享:http://www.5511xx.com/article/cdiehps.html