Spring中Feign的调用流程详解
作者:dalianpai
这篇文章主要介绍了Spring中Feign的调用流程详解,分析过了创建的代理是FeignInvocationHandler,那我们就打断点,停在它的反射方法上,看看到底做了什么,需要的朋友可以参考下
Feign的调用流程
动态代理的入口
前面已经分析过了创建的代理是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方法的集合,这里更加方法去获取,然后调用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; } } }
第一行首先会创建出一个template的,它的结果如下图:
最终把上面获取到的2个变量带到了executeAndDecode方法,这个方法才是执行和解码的方法。
Object executeAndDecode(RequestTemplate template, Options options) throws Throwable { //这里的request就已经把服务名给加上了,变成了一个具体的请求。 Request request = targetRequest(template); if (logLevel != Logger.Level.NONE) { logger.logRequest(metadata.configKey(), logLevel, request); } Response response; long start = System.nanoTime(); try { //来到了这里,无论是负载均衡还是请求响应都是这边完成的,那我们就点进去看看。 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是如何实现负载均衡的
先进入到前面的lbClient方法,返回一个FeignLoadBalancer,说明这里和ribbon结合了。
private FeignLoadBalancer lbClient(String clientName) { return this.lbClientFactory.create(clientName); }
此处调用了一个create方法,那就进去看看。
注意这里的factory,其实就是SpringClientFactory,从它里面获取了lb,lb里面包含了注册的服务清单,然后再把它放到本地的缓存当中。
接着就会执行,现在它的sumbit方法中打一个断点:
发现里面会执行一个selectServer()方法,肯定是这个里面选择了服务
在点进去看看,于是就找到了ribbon中熟悉的方法了,就是这里选择了那个服务
选择好了那个服务,就继续放下走,开始这边拼接ip和url了
会把选择的ip和后面请求的url都传进来。
在其父类的reconstructURIWithServer方法中完成了拼接,如下图:
后面就是请求响应和解码了
到此这篇关于Spring中Feign的调用流程详解的文章就介绍到这了,更多相关Feign的调用流程内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!