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
這個應該是最終的了,首先會對一個url
做MD5
,對這個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
次,所以有三個結果,只有最後一次是有內容的。
好了,今天就到這裏了,希望對學習理解有幫助,大神看見勿噴,僅爲自己的學習理解,能力有限,請多包涵。