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-06Java ThreadLocal詳解_動力節(jié)點Java學(xué)院整理
ThreadLocal,很多地方叫做線程本地變量,也有些地方叫做線程本地存儲,本文會詳細的介紹一下,有興趣的可以了解一下2017-06-06