欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

使用Java自制一個一個Nacos

 更新時間:2024年01月19日 09:52:36   作者:樂樂家的樂樂  
Nacos是?Dynamic?Naming?and?Configuration?Service的首字母簡稱,一個更易于構(gòu)建云原生應用的動態(tài)服務發(fā)現(xiàn)、配置管理和服務管理平臺,本文將嘗試用Java實現(xiàn)一個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的資料請關注腳本之家其它相關文章!

相關文章

最新評論