使用Java自制一個一個Nacos
什么是Nacos
Nacos是 Dynamic Naming and Configuration Service的首字母簡稱,一個更易于構(gòu)建云原生應用的動態(tài)服務發(fā)現(xiàn)、配置管理和服務管理平臺。
Nacos的主要功能:
- 服務發(fā)現(xiàn)和服務健康監(jiān)測
- 動態(tài)配置服務
- 動態(tài) DNS 服務
- 服務及其元數(shù)據(jù)管理
直接參考Nacos文檔 :Nacos文檔
我們要做的功能是
Nacos的功能實在是太成熟了,但是我們可以通過官網(wǎng)和文檔總結(jié)出Nacos的兩大核心功能:
- 服務發(fā)現(xiàn)
- 配置管理
一、實現(xiàn) 服務發(fā)現(xiàn)
服務發(fā)現(xiàn),與其說是實現(xiàn)服務與發(fā)現(xiàn),不如說是實現(xiàn)以下三個功能:
- 服務啟動時候進行注冊
- 查詢已注冊服務信息
- 確認服務狀態(tài)是否健康
1、創(chuàng)建一個SpringBoot項目,用來做服務端
這個項目要實現(xiàn)幾個目的:
- 首先我們的服務需要可以支持Http請求(GRPC更好,Nacos用的就是GRPC,Http請求我們更熟悉一點,以后我們會專門出有關于JAVA使用GRPC的文章)。
- 其次我們需要我們的服務可以集成和連接一個關系型數(shù)據(jù)庫(Mysql或者Oracle...)和非關系型數(shù)據(jù)庫(Redis...)
所以我們需要創(chuàng)建一個SringBoot項目,因為我們需要一個配置與發(fā)現(xiàn)中心的這么一個服務,類似于搭建Nacos,我們只不過是將這個中間件變成一個我們熟悉的SpringBoot項目,方便我們開發(fā)。
2、服務端
在 注冊中心 服務端 ,我們需要一個注冊接口。
實例 數(shù)據(jù)庫同理創(chuàng)建
public class ClientBody { private static final long serialVersionUID=1L; /** 自增id */ private Long id; /** 項目名 */ private String projectName; /** 端口 */ private String port; /** 健康檢測回調(diào)接口 */ private String CallbackInterface; /** 內(nèi)網(wǎng)ip */ private String inNetIp; /** 外網(wǎng)ip */ private String outNetIp; /** 注冊時間 */ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date regSerTime; /** 0-健康 1-異常 2-死亡 */ private String serType; /** 異常時間 */ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date exceptTime; /** 死亡時間 */ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date deathTime; /** 檢測次數(shù) */ private Long checkNum; /** 異常次數(shù) */ private Long exceNum; }
服務端注冊接口
/** * 令牌自定義標識 */ @Value("${token.header}") private String header; /** * 服務注冊 */ @PostMapping("/serviceRegistration") public Boolean add(HttpServletRequest request, @RequestBody ClientBody clientBody){ /** * 獲取token */ String token = request.getHeader("header"); /** * 驗證請求合法性 */ Boolean isLegal = SecurityUtils.verLegal(token); if(isLegal){ /** * 檢測 serType!=2 端口+內(nèi)網(wǎng)地址 */ ClientBody client = clientBodyService.checkClient(clientBody); if(ObjectUtils.isNotEmpty(client)){ /** * 說明是在心跳檢測期間重新啟動。 * 注銷這臺實例. * * Mysql client 這條數(shù)據(jù) * deathTime 改為現(xiàn)在時間 * serType 改為 2 * * Redis 直接刪除這個數(shù)據(jù)id 為 Key的數(shù)據(jù) * 直接刪除這臺實例 */ clientBodyService.logoutCient(client); /** * redis 和 Mysql 中新增一臺實例 * regSerTime 現(xiàn)在時間 * serType 為 0 */ clientBodyService.insert(clientBody); }else{ /** * 啟動了一臺實例 */ clientBodyService.insert(clientBody); } return true; }else{ return false; } }
服務端健康檢測定時任務
/** * 60秒定時健康檢測 */ @Scheduled(cron = "0/60 * * * * ?") public void heartbeatCheck(){ /** * 查詢 serType = 0 健康的 實例List */ List<ClientBody> clientBodyList = clientBodyService.selectOnlineServer(); for (ClientBody clientBody : clientBodyList) { //回調(diào)接口 String CallbackInterface = clientBody.getCallbackInterface(); //內(nèi)網(wǎng)地址 String inNetIp = clientBody.getInNetIp(); //拿到端口號 String port = clientBody.getPort(); //發(fā)送http請求 true為正常 false為異常 Boolean state = HttpUtils.sendHead(CallbackInterface,inNetIp,port); if(state){ //檢測次數(shù) + 1(checkNum + 1) clientBodyService.updateCientNormal(clientBody); }else{ /** * 檢測ping不通原因可能時網(wǎng)絡波動 * 檢測十次 都是異常 才判定死亡 */ if(clientBody.getCheckNum() > 10){ //修改這條數(shù)據(jù)為死亡 (serType = 2) clientBodyService.updateCientDeath(clientBody); }else{ //修改這條數(shù)據(jù)為異常,然后檢測次數(shù) + 1,異常次數(shù) + 1,異常時間[現(xiàn)在時間字符串拼接在原有數(shù)據(jù)之后](serType = 1;checkNum + 1;exceNum + 1;) clientBodyService.updateCientException(clientBody); } } } }
3、客戶端
在我們的 客戶端服務 我們需要在啟動的時候注冊:
客戶端注冊接口
/** * 注冊 * @PostConstruct 解釋:在項目啟動時加載數(shù)據(jù) */ @PostConstruct public void registerService(){ HashMap<String, Object> map = new HashMap<String,Object>(){{ //項目名 put("projectName",MyConfig.getName()); //我注冊選擇內(nèi)網(wǎng)地址,這個可以根據(jù)自己項目的實際情況選用。 put("inNetIp", MyConfig.getUrl()); //回調(diào)接口,這個接口就是下邊的健康檢測接口 put("CallbackInterface", "/checkHealthy"); //項目端口號 put("port", MyConfig.getPort()); }}; AjaxResult ajaxResult = HttpUtils.sendPostRequest('注冊與配置中心url', "/serviceRegistration", map); }
我們還需要一個健康檢測客戶端接口,以便于服務注冊中心心跳檢測。我們選擇用輕量級的頭請求。
客戶端健康檢測接口
好了,我們的服務注冊就完成了!
二、實現(xiàn) 配置管理
配置管理只需要我們完成兩件事情
- 服務端管理配置
- 客戶端啟動的時候拉取配置
1、服務端管理配置
第一步我們需要在服務注冊中心 服務端管理配置,我們將所有application.yml中的文件用properties的方式存入數(shù)據(jù)庫。
/** * 健康檢測接口 */ @RequestMapping(value = "/CallbackInterface",method = RequestMethod.HEAD) public void healthyByHead(HttpServletResponse response) { response.setHeader("data","200"); }
入庫的形式就是這種:
服務端拉取配置接口
public class ConfigData { private static final long serialVersionUID=1L; /** id */ private Long id; /** key */ private String key; /** value */ private String value; /** tag */ private String tag; /** remark */ private String remark; }
2、客戶端拉取配置
客戶端拉取配置接口,我們客戶端程序啟動的時候需要從注冊服務中心來拉取配置。
首先我們在路徑src\main\resources\META-INF\spring.factories
中的spring.factories
文件中加入到最后一行。
@GetMapping("/getConfigDataByTag") public List<Map<String, String>> getConfig(@RequestParam String tag) throws JsonProcessingException { Map<String, String> configData = configDataService.selectconfigDataList(new configData(tag)); return list; }
然后我們需要創(chuàng)建一個拉取配置文件的類ServerConfigProcessor
實現(xiàn)EnvironmentPostProcessor
public class ServerConfigProcessor implements EnvironmentPostProcessor { private static final String PROPERTY_SOURCE_NAME = "databaseProperties"; @Override public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { log.info("ServerConfig loading start"); Map<String, Object> propertySource = new HashMap<>(); try { /** * 拉取配置 * MyConfig.ServerConfigHttpUrl 服務端url * MyConfig.ServerConfigInterface 服務端接口 * MyConfig.MyServerTag 本服務標識(用來判斷拉取的配置條件) */ Map<String, Object> configSource = HttpUtils.sendGet(MyConfig.ServerConfigHttpUrl,MyConfig.ServerConfigInterface,MyConfig.MyServerTag); propertySource.putAll(configSource); environment.getPropertySources().addFirst(new MapPropertySource(PROPERTY_SOURCE_NAME, propertySource)); log.info("ServerConfig loading Success"); } catch (Throwable e) { e.printStackTrace(); throw new RuntimeException(e); } } }
OK到此為止我們的自定義Nacos就做好了。
總結(jié)
我們的自定義Nacos就做好了,它可以實現(xiàn)的功能有:
- 客戶端啟動可以注冊到服務端。
- 服務端可以心跳檢測每個客戶端的項目。
- 數(shù)據(jù)分析,比如我們什么時候項目異常?總共啟動多少次項目?...
- 可以不用application.yml,配置文件全部放在數(shù)據(jù)庫中。(和Nacos一樣)
- 可以實現(xiàn)熱部署配置文件,遠程更改,實時有效。
其他問題
src\main\resources\META-INF\spring.factories為什么可以自動裝載配置?
這就要涉及SpringBoot源碼啦,關于SpringBoot啟動時候加載配置的優(yōu)先級和環(huán)境配置的上下文,請參考SpringBoot源碼。(讀源碼啦~ 必須要過這一關的嘛)
自定義拓展功能
可以把服務注冊發(fā)現(xiàn)和配置管理都用前端展示到頁面上方便管理。以下是我自己實現(xiàn)的前端界面,不美觀無所謂,看的懂就行。
服務注冊發(fā)現(xiàn)
配置管理(可以和Nacos一樣在頁面進行修改和熱部署)
以上就是使用Java自制一個一個Nacos的詳細內(nèi)容,更多關于Java Nacos的資料請關注腳本之家其它相關文章!
相關文章
java模擬TCP通信實現(xiàn)客戶端上傳文件到服務器端
這篇文章主要為大家詳細介紹了java模擬TCP通信實現(xiàn)客戶端上傳文件到服務器端,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-10-10Java實現(xiàn)給網(wǎng)站上傳圖片蓋章的方法
這篇文章主要介紹了Java實現(xiàn)給網(wǎng)站上傳圖片蓋章的方法,涉及java針對圖片的合成操作技巧,類似水印功能,需要的朋友可以參考下2015-07-07JAVA Comparator 和 Comparable接口使用方法
本文介紹了Java中Comparable和Comparator接口的使用,包括它們的定義、方法和應用場景,Comparable用于定義類的自然排序規(guī)則,而Comparator提供了一種靈活的方式來定義對象之間的排序規(guī)則,無需修改類本身,感興趣的朋友一起看看吧2025-03-03Java遞歸算法經(jīng)典實例(經(jīng)典兔子問題)
本文主要對經(jīng)典的兔子案例分析,來進一步更好的理解和學習java遞歸算法,具有很好的參考價值,需要的朋友一起來看下吧2016-12-12Java LocalCache 本地緩存的實現(xiàn)實例
本篇文章主要介紹了Java LocalCache 本地緩存的實現(xiàn)實例,具有一定的參考價值,感興趣的小伙伴們可以參考一下。2017-05-05springcloud gateway網(wǎng)關服務啟動報錯的解決
這篇文章主要介紹了springcloud gateway網(wǎng)關服務啟動報錯的解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03