Spring中Feign的調(diào)用流程詳解
Feign的調(diào)用流程
動態(tài)代理的入口
前面已經(jīng)分析過了創(chuàng)建的代理是FeignInvocationHandler,那我們就打斷點,停在它的反射方法上,看看到底做了什么。
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("equals".equals(method.getName())) {
try {
Object otherHandler =
args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
return equals(otherHandler);
} catch (IllegalArgumentException e) {
return false;
}
} else if ("hashCode".equals(method.getName())) {
return hashCode();
} else if ("toString".equals(method.getName())) {
return toString();
}
return dispatch.get(method).invoke(args);
}dispatch此處就是之前封裝的5個SynchronousMethodHandler方法的集合,這里更加方法去獲取,然后調(diào)用invoke方法。來到了SynchronousMethodHandler這個方法。
@Override
public Object invoke(Object[] argv) throws Throwable {
RequestTemplate template = buildTemplateFromArgs.create(argv);
Options options = findOptions(argv);
Retryer retryer = this.retryer.clone();
while (true) {
try {
return executeAndDecode(template, options);
} catch (RetryableException e) {
try {
retryer.continueOrPropagate(e);
} catch (RetryableException th) {
Throwable cause = th.getCause();
if (propagationPolicy == UNWRAP && cause != null) {
throw cause;
} else {
throw th;
}
}
if (logLevel != Logger.Level.NONE) {
logger.logRetry(metadata.configKey(), logLevel);
}
continue;
}
}
}第一行首先會創(chuàng)建出一個template的,它的結(jié)果如下圖:

最終把上面獲取到的2個變量帶到了executeAndDecode方法,這個方法才是執(zhí)行和解碼的方法。
Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
//這里的request就已經(jīng)把服務(wù)名給加上了,變成了一個具體的請求。
Request request = targetRequest(template);
if (logLevel != Logger.Level.NONE) {
logger.logRequest(metadata.configKey(), logLevel, request);
}
Response response;
long start = System.nanoTime();
try {
//來到了這里,無論是負載均衡還是請求響應(yīng)都是這邊完成的,那我們就點進去看看。
response = client.execute(request, options);
// ensure the request is set. TODO: remove in Feign 12
response = response.toBuilder()
.request(request)
.requestTemplate(template)
.build();
} catch (IOException e) {
if (logLevel != Logger.Level.NONE) {
logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime(start));
}
throw errorExecuting(request, e);
}
long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
if (decoder != null)
return decoder.decode(response, metadata.returnType());
CompletableFuture<Object> resultFuture = new CompletableFuture<>();
asyncResponseHandler.handleResponse(resultFuture, metadata.configKey(), response,
metadata.returnType(),
elapsedTime);
try {
if (!resultFuture.isDone())
throw new IllegalStateException("Response handling not done");
return resultFuture.join();
} catch (CompletionException e) {
Throwable cause = e.getCause();
if (cause != null)
throw cause;
throw e;
}
}

Feign是如何實現(xiàn)負載均衡的


先進入到前面的lbClient方法,返回一個FeignLoadBalancer,說明這里和ribbon結(jié)合了。
private FeignLoadBalancer lbClient(String clientName) {
return this.lbClientFactory.create(clientName);
}此處調(diào)用了一個create方法,那就進去看看。

注意這里的factory,其實就是SpringClientFactory,從它里面獲取了lb,lb里面包含了注冊的服務(wù)清單,然后再把它放到本地的緩存當(dāng)中。

接著就會執(zhí)行,現(xiàn)在它的sumbit方法中打一個斷點:

發(fā)現(xiàn)里面會執(zhí)行一個selectServer()方法,肯定是這個里面選擇了服務(wù)

在點進去看看,于是就找到了ribbon中熟悉的方法了,就是這里選擇了那個服務(wù)

選擇好了那個服務(wù),就繼續(xù)放下走,開始這邊拼接ip和url了

會把選擇的ip和后面請求的url都傳進來。

在其父類的reconstructURIWithServer方法中完成了拼接,如下圖:

后面就是請求響應(yīng)和解碼了
到此這篇關(guān)于Spring中Feign的調(diào)用流程詳解的文章就介紹到這了,更多相關(guān)Feign的調(diào)用流程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
最新hadoop安裝教程及hadoop的命令使用(親測可用)
這篇文章主要介紹了最新hadoop安裝教程(親測可用),本文主要講解了如何安裝hadoop、使用hadoop的命令及遇到的問題解決,需要的朋友可以參考下2022-06-06
Java ThreadLocal詳解_動力節(jié)點Java學(xué)院整理
ThreadLocal,很多地方叫做線程本地變量,也有些地方叫做線程本地存儲,本文會詳細的介紹一下,有興趣的可以了解一下2017-06-06

