Spring Cloud 2.2.2 源碼之二十九nacos客戶端獲取配置原理四

MetricsHttpAgent的httpGet

封裝了一層計時,內部還是HttpAgent去請求。

    @Override
    public HttpResult httpGet(String path, List<String> headers, List<String> paramValues, String encoding, long readTimeoutMs) throws IOException {
        Histogram.Timer timer = MetricsMonitor.getConfigRequestMonitor("GET", path, "NA");
        HttpResult result = null;
        try {
            result = httpAgent.httpGet(path, headers, paramValues, encoding, readTimeoutMs);
        } catch (IOException e) {
            throw e;
        } finally {
            timer.observeDuration();
            timer.close();
        }

        return result;
    }

ServerHttpAgent的httpGet

設置一些參數信息,最後請求http://xxxxxx:xxxx/nacos/v1/cs/configs,帶上參數,使用HttpSimpleClient.httpGet,然後根據返回設置當前的服務器地址,如果一個服務器請求失敗,就嘗試獲取下一個服務器地址,繼續請求。但是有嘗試次數和超時限制。

    @Override
    public HttpResult httpGet(String path, List<String> headers, List<String> paramValues, String encoding,
                              long readTimeoutMs) throws IOException {
        final long endTime = System.currentTimeMillis() + readTimeoutMs;//超時時間
        final boolean isSSL = false;
        injectSecurityInfo(paramValues);//安全信息,accessToken,tenant等
        String currentServerAddr = serverListMgr.getCurrentServerAddr();//當前服務器地址
        int maxRetry = this.maxRetry;//默認3次最大請求次數

        do {
            try {
                List<String> newHeaders = getSpasHeaders(paramValues);
                if (headers != null) {
                    newHeaders.addAll(headers);//頭信息
                }
                HttpResult result = HttpSimpleClient.httpGet(
                    getUrl(currentServerAddr, path), newHeaders, paramValues, encoding,
                    readTimeoutMs, isSSL);
                if (result.code == HttpURLConnection.HTTP_INTERNAL_ERROR
                    || result.code == HttpURLConnection.HTTP_BAD_GATEWAY
                    || result.code == HttpURLConnection.HTTP_UNAVAILABLE) {
                    LOGGER.error("[NACOS ConnectException] currentServerAddr: {}, httpCode: {}",
                        serverListMgr.getCurrentServerAddr(), result.code);
                } else {
                    // 可用就更新
                    serverListMgr.updateCurrentServerAddr(currentServerAddr);
                    return result;
                }
            } catch (ConnectException ce) {
             	...
            }

            if (serverListMgr.getIterator().hasNext()) {
                currentServerAddr = serverListMgr.getIterator().next();
            } else {
                maxRetry--;//次數限制
                if (maxRetry < 0) {
                    throw new ConnectException("[NACOS HTTP-GET] The maximum number of tolerable server reconnection errors has been reached");
                }
                serverListMgr.refreshCurrentServerAddr();
            }

        } while (System.currentTimeMillis() <= endTime);//超時限制

        LOGGER.error("no available server");
        throw new ConnectException("no available server");
    }

HttpSimpleClient的httpGet

這個應該是最終的了,首先會對一個urlMD5,對這個MD5值做檢查,有一個頻率的限制,默認每秒5次請求。剩下的就是用URL去請求啦,然後讀取流信息。

static public HttpResult httpGet(String url, List<String> headers, List<String> paramValues,
                                     String encoding, long readTimeoutMs, boolean isSSL) throws IOException {
        String encodedContent = encodingParams(paramValues, encoding);
        url += (null == encodedContent) ? "" : ("?" + encodedContent);
        if (Limiter.isLimit(MD5.getInstance().getMD5String(
            new StringBuilder(url).append(encodedContent).toString()))) {
            return new HttpResult(NacosException.CLIENT_OVER_THRESHOLD,
                "More than client-side current limit threshold");
        }

        HttpURLConnection conn = null;

        try {
            conn = (HttpURLConnection) new URL(url).openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(ParamUtil.getConnectTimeout() > 100 ? ParamUtil.getConnectTimeout() : 100);
            conn.setReadTimeout((int) readTimeoutMs);
            List<String> newHeaders = getHeaders(url, headers, paramValues);
            setHeaders(conn, newHeaders, encoding);

            conn.connect();

            int respCode = conn.getResponseCode();
            String resp = null;

            if (HttpURLConnection.HTTP_OK == respCode) {
                resp = IoUtils.toString(conn.getInputStream(), encoding);
            } else {
                resp = IoUtils.toString(conn.getErrorStream(), encoding);
            }
            return new HttpResult(respCode, conn.getHeaderFields(), resp);
        } finally {
            IoUtils.closeQuietly(conn);
        }
    }

狀態碼處理

最後根據狀態碼會有一些處理,比如保存內容,保存相應頭的Config-Type信息。

  switch (result.code) {
            case HttpURLConnection.HTTP_OK:
            	//保存快照
                LocalConfigInfoProcessor.saveSnapshot(agent.getName(), dataId, group, tenant, result.content);
                ct[0] = result.content;//取出內容
                if (result.headers.containsKey(CONFIG_TYPE)) {
                    ct[1] = result.headers.get(CONFIG_TYPE).get(0);//取出類型
                } else {
                    ct[1] = ConfigType.TEXT.getType();
                }
                return ct;
            case HttpURLConnection.HTTP_NOT_FOUND://保存快照
                LocalConfigInfoProcessor.saveSnapshot(agent.getName(), dataId, group, tenant, null);
                return ct;
            case HttpURLConnection.HTTP_CONFLICT: {
                LOGGER.error(
                    "[{}] [sub-server-error] get server config being modified concurrently, dataId={}, group={}, "
                        + "tenant={}", agent.getName(), dataId, group, tenant);
                throw new NacosException(NacosException.CONFLICT,
                    "data being modified, dataId=" + dataId + ",group=" + group + ",tenant=" + tenant);
            }
            case HttpURLConnection.HTTP_FORBIDDEN: {
                LOGGER.error("[{}] [sub-server-error] no right, dataId={}, group={}, tenant={}", agent.getName(), dataId,
                    group, tenant);
                throw new NacosException(result.code, result.content);
            }
            default: {
                LOGGER.error("[{}] [sub-server-error]  dataId={}, group={}, tenant={}, code={}", agent.getName(), dataId,
                    group, tenant, result.code);
                throw new NacosException(result.code,
                    "http error, code=" + result.code + ",dataId=" + dataId + ",group=" + group + ",tenant=" + tenant);
            }

結果處理

然後把結果寫進響應ConfigResponse裏,進行過濾,返回結果內容:
在這裏插入圖片描述

解析

根據後綴名選擇解析器,解析器用鏈表連起來的,從頭開始,哪個可以可以解析後綴就用哪個解析出內容,封裝成LinkedHashMap返回,具體就不看啦。
在這裏插入圖片描述
解析器:
在這裏插入圖片描述
單鏈表的結構:
在這裏插入圖片描述
至此就完成了locate方法,結果被封裝成CompositePropertySource返回了,因爲這裏有嘗試3次,所以有三個結果,只有最後一次是有內容的。
在這裏插入圖片描述

好了,今天就到這裏了,希望對學習理解有幫助,大神看見勿噴,僅爲自己的學習理解,能力有限,請多包涵。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章