如何解析Feign在RPC调用中结合Ribbon负载均衡的源码实现?

2026-04-28 15:532阅读0评论SEO资讯
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1031个文字,预计阅读时间需要5分钟。

如何解析Feign在RPC调用中结合Ribbon负载均衡的源码实现?

Feign 客户端接口的动态代理是基于 JDK 动态代理实现的,它将所有方法调用最终都代理到 InvocationHandler 接口的实现。默认情况下,这个实现是 ReflectiveFeign.FeignInvocation。

转载请注明出处:  

  Feign客户端接口的动态代理生成是基于JDK的动态代理来实现的,那么在所有的方法调用的时候最终都会走InvocationHandler接口的实现,默认就是ReflectiveFeign.FeignInvocationHandler,那我们接下来就来看看,FeignInvocationHandler是如何实现rpc调用的。

  FeignInvocationHandler对于invoke方法的实现。

public class ReflectiveFeign extends Feign { static class FeignInvocationHandler implements InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (!"equals".equals(method.getName())) { if ("hashCode".equals(method.getName())) { return this.hashCode(); } else { return "toString".equals(method.getName()) ? this.toString() : ((MethodHandler)this.dispatch.get(method)).invoke(args); } } else { try { Object otherHandler = args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null; return this.equals(otherHandler); } catch (IllegalArgumentException var5) { return false; } } } }

  实现rpc 调用的方法是 this.dispatch.get(method)).invoke(args)

  从dispatch获取要调用的方法对应的MethodHandler,然后调用MethodHandler的invoke方法。那MethodHandler是什么时候生成的呢?MethodHandler是在构建动态代理的时候生成的, 那MethodHandler作用是什么呢?你可以理解为最终rpc的调用都是基于这个MethodHandler来实现的,每个方法都有对应MethodHandler来实现rpc调用,接下来我们就来看一下MethodHandler的invoke方法的实现。

  MethodHandler是个接口,有两个实现类,一个是DefaultMethodHandler,这个是处理接口中的默认方法的,另一个是SynchronousMethodHandler,这个是实现rpc调用的方法。接下来我们就看看SynchronousMethodHandler关于invoke方法的实现。

public Object invoke(Object[] argv) throws Throwable { // 构建了一个RequestTemplate,RequestTemplate可以看成是组装")) {   newUrl = originalUrl.substring(0, 8) + originalUrl.substring(8 + host.length()); } else if (originalUrl.startsWith("") && newUrl.length() == 8)|| (newUrl.startsWith("") && newUrl.length() == 7)) {   buffer.append("/"); }   return URI.create(buffer.toString()); } @Override public Response execute(Request request, Request.Options options) throws IOException { try { URI asUri = URI.create(request.url()); String clientName = asUri.getHost(); URI uriWithoutHost = cleanUrl(request.url(), clientName); FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest( this.delegate, request, uriWithoutHost); IClientConfig requestConfig = getClientConfig(options, clientName); return lbClient(clientName) .executeWithLoadBalancer(ribbonRequest, requestConfig).toResponse(); } catch (ClientException e) { IOException io = findIOException(e); if (io != null) { throw io; } throw new RuntimeException(e); } } IClientConfig getClientConfig(Request.Options options, String clientName) { IClientConfig requestConfig; if (options == DEFAULT_OPTIONS) { requestConfig = this.clientFactory.getClientConfig(clientName); } else { requestConfig = new FeignOptionsClientConfig(options); } return requestConfig; } protected IOException findIOException(Throwable t) { if (t == null) { return null; } if (t instanceof IOException) { return (IOException) t; } return findIOException(t.getCause()); } public Client getDelegate() { return this.delegate; } private FeignLoadBalancer lbClient(String clientName) { return this.lbClientFactory.create(clientName); } static class FeignOptionsClientConfig extends DefaultClientConfigImpl { FeignOptionsClientConfig(Request.Options options) { setProperty(CommonClientConfigKey.ConnectTimeout, options.connectTimeoutMillis()); setProperty(CommonClientConfigKey.ReadTimeout, options.readTimeoutMillis()); } @Override public void loadProperties(String clientName) { } @Override public void loadDefaultValues() { } } }

  在动态代理调用的那里我们得出一个结论,那就是最后会调用Client接口的execute方法的实现,所以我们就看一下execute方法的实现,这里就是一堆操作,从请求的URL中拿到了clientName,也就是服务名。

  为什么可以拿到服务名?

  其实很简单,OpenFeign构建动态代理的时候,传入了一个HardCodedTarget,当时说在构建HardCodedTarget的时候传入了一个url,那个url当时说了其实就是服务名,所以到这里,虽然有具体的请求接口的路径,但是还是类似 服务名/api/sayHello这种,所以可以通过路径拿到你锁请求的服务名。

  拿到服务名之后,再拿到了一个配置类IClientConfig,最后调用lbClient,我们看一下lbClient的方法实现。

private FeignLoadBalancer lbClient(String clientName) { // 调用CachingSpringLoadBalancerFactory的create方法,从缓存中获取一个FeignLoadBalancer,获取不到就创建一个 return this.lbClientFactory.create(clientName); }



3.查看 FeignLoadBalancer 源码

  核心源码:

public class FeignLoadBalancer extends AbstractLoadBalancerAwareClient<FeignLoadBalancer.RibbonRequest, FeignLoadBalancer.RibbonResponse> { private final RibbonProperties ribbon; protected int connectTimeout; protected int readTimeout; protected IClientConfig clientConfig; protected ServerIntrospector serverIntrospector; public FeignLoadBalancer(ILoadBalancer lb, IClientConfig clientConfig, ServerIntrospector serverIntrospector) { super(lb, clientConfig); this.setRetryHandler(RetryHandler.DEFAULT); this.clientConfig = clientConfig; this.ribbon = RibbonProperties.from(clientConfig); RibbonProperties ribbon = this.ribbon; this.connectTimeout = ribbon.getConnectTimeout(); this.readTimeout = ribbon.getReadTimeout(); this.serverIntrospector = serverIntrospector; } @Override public RibbonResponse execute(RibbonRequest request, IClientConfig configOverride) throws IOException { Request.Options options; if (configOverride != null) { RibbonProperties override = RibbonProperties.from(configOverride); options = new Request.Options(override.connectTimeout(this.connectTimeout), override.readTimeout(this.readTimeout)); } else { options = new Request.Options(this.connectTimeout, this.readTimeout); } Response response = request.client().execute(request.toRequest(), options); return new RibbonResponse(request.getUri(), response); } }

  FeignLoadBalancer继承自AbstractLoadBalancerAwareClient,AbstractLoadBalancerAwareClient类主要作用是通过ILoadBalancer组件获取一个Server,然后基于这个Server重构了URI,也就是将你的请求路径服务名/api/sayHello转换成类似192.168.1.101:8088/api/sayHello这种路径,也就是将原服务名替换成服务所在的某一台机器ip和端口,替换之后就交由子类实现的exceut方法来发送blog.csdn.net/u010342147/article/details/123669493

如何解析Feign在RPC调用中结合Ribbon负载均衡的源码实现?

  blog.csdn.net/weixin_45630885/article/details/124391934

  blog.csdn.net/weixin_45630885/article/details/124533413

本文共计1031个文字,预计阅读时间需要5分钟。

如何解析Feign在RPC调用中结合Ribbon负载均衡的源码实现?

Feign 客户端接口的动态代理是基于 JDK 动态代理实现的,它将所有方法调用最终都代理到 InvocationHandler 接口的实现。默认情况下,这个实现是 ReflectiveFeign.FeignInvocation。

转载请注明出处:  

  Feign客户端接口的动态代理生成是基于JDK的动态代理来实现的,那么在所有的方法调用的时候最终都会走InvocationHandler接口的实现,默认就是ReflectiveFeign.FeignInvocationHandler,那我们接下来就来看看,FeignInvocationHandler是如何实现rpc调用的。

  FeignInvocationHandler对于invoke方法的实现。

public class ReflectiveFeign extends Feign { static class FeignInvocationHandler implements InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (!"equals".equals(method.getName())) { if ("hashCode".equals(method.getName())) { return this.hashCode(); } else { return "toString".equals(method.getName()) ? this.toString() : ((MethodHandler)this.dispatch.get(method)).invoke(args); } } else { try { Object otherHandler = args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null; return this.equals(otherHandler); } catch (IllegalArgumentException var5) { return false; } } } }

  实现rpc 调用的方法是 this.dispatch.get(method)).invoke(args)

  从dispatch获取要调用的方法对应的MethodHandler,然后调用MethodHandler的invoke方法。那MethodHandler是什么时候生成的呢?MethodHandler是在构建动态代理的时候生成的, 那MethodHandler作用是什么呢?你可以理解为最终rpc的调用都是基于这个MethodHandler来实现的,每个方法都有对应MethodHandler来实现rpc调用,接下来我们就来看一下MethodHandler的invoke方法的实现。

  MethodHandler是个接口,有两个实现类,一个是DefaultMethodHandler,这个是处理接口中的默认方法的,另一个是SynchronousMethodHandler,这个是实现rpc调用的方法。接下来我们就看看SynchronousMethodHandler关于invoke方法的实现。

public Object invoke(Object[] argv) throws Throwable { // 构建了一个RequestTemplate,RequestTemplate可以看成是组装")) {   newUrl = originalUrl.substring(0, 8) + originalUrl.substring(8 + host.length()); } else if (originalUrl.startsWith("") && newUrl.length() == 8)|| (newUrl.startsWith("") && newUrl.length() == 7)) {   buffer.append("/"); }   return URI.create(buffer.toString()); } @Override public Response execute(Request request, Request.Options options) throws IOException { try { URI asUri = URI.create(request.url()); String clientName = asUri.getHost(); URI uriWithoutHost = cleanUrl(request.url(), clientName); FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest( this.delegate, request, uriWithoutHost); IClientConfig requestConfig = getClientConfig(options, clientName); return lbClient(clientName) .executeWithLoadBalancer(ribbonRequest, requestConfig).toResponse(); } catch (ClientException e) { IOException io = findIOException(e); if (io != null) { throw io; } throw new RuntimeException(e); } } IClientConfig getClientConfig(Request.Options options, String clientName) { IClientConfig requestConfig; if (options == DEFAULT_OPTIONS) { requestConfig = this.clientFactory.getClientConfig(clientName); } else { requestConfig = new FeignOptionsClientConfig(options); } return requestConfig; } protected IOException findIOException(Throwable t) { if (t == null) { return null; } if (t instanceof IOException) { return (IOException) t; } return findIOException(t.getCause()); } public Client getDelegate() { return this.delegate; } private FeignLoadBalancer lbClient(String clientName) { return this.lbClientFactory.create(clientName); } static class FeignOptionsClientConfig extends DefaultClientConfigImpl { FeignOptionsClientConfig(Request.Options options) { setProperty(CommonClientConfigKey.ConnectTimeout, options.connectTimeoutMillis()); setProperty(CommonClientConfigKey.ReadTimeout, options.readTimeoutMillis()); } @Override public void loadProperties(String clientName) { } @Override public void loadDefaultValues() { } } }

  在动态代理调用的那里我们得出一个结论,那就是最后会调用Client接口的execute方法的实现,所以我们就看一下execute方法的实现,这里就是一堆操作,从请求的URL中拿到了clientName,也就是服务名。

  为什么可以拿到服务名?

  其实很简单,OpenFeign构建动态代理的时候,传入了一个HardCodedTarget,当时说在构建HardCodedTarget的时候传入了一个url,那个url当时说了其实就是服务名,所以到这里,虽然有具体的请求接口的路径,但是还是类似 服务名/api/sayHello这种,所以可以通过路径拿到你锁请求的服务名。

  拿到服务名之后,再拿到了一个配置类IClientConfig,最后调用lbClient,我们看一下lbClient的方法实现。

private FeignLoadBalancer lbClient(String clientName) { // 调用CachingSpringLoadBalancerFactory的create方法,从缓存中获取一个FeignLoadBalancer,获取不到就创建一个 return this.lbClientFactory.create(clientName); }



3.查看 FeignLoadBalancer 源码

  核心源码:

public class FeignLoadBalancer extends AbstractLoadBalancerAwareClient<FeignLoadBalancer.RibbonRequest, FeignLoadBalancer.RibbonResponse> { private final RibbonProperties ribbon; protected int connectTimeout; protected int readTimeout; protected IClientConfig clientConfig; protected ServerIntrospector serverIntrospector; public FeignLoadBalancer(ILoadBalancer lb, IClientConfig clientConfig, ServerIntrospector serverIntrospector) { super(lb, clientConfig); this.setRetryHandler(RetryHandler.DEFAULT); this.clientConfig = clientConfig; this.ribbon = RibbonProperties.from(clientConfig); RibbonProperties ribbon = this.ribbon; this.connectTimeout = ribbon.getConnectTimeout(); this.readTimeout = ribbon.getReadTimeout(); this.serverIntrospector = serverIntrospector; } @Override public RibbonResponse execute(RibbonRequest request, IClientConfig configOverride) throws IOException { Request.Options options; if (configOverride != null) { RibbonProperties override = RibbonProperties.from(configOverride); options = new Request.Options(override.connectTimeout(this.connectTimeout), override.readTimeout(this.readTimeout)); } else { options = new Request.Options(this.connectTimeout, this.readTimeout); } Response response = request.client().execute(request.toRequest(), options); return new RibbonResponse(request.getUri(), response); } }

  FeignLoadBalancer继承自AbstractLoadBalancerAwareClient,AbstractLoadBalancerAwareClient类主要作用是通过ILoadBalancer组件获取一个Server,然后基于这个Server重构了URI,也就是将你的请求路径服务名/api/sayHello转换成类似192.168.1.101:8088/api/sayHello这种路径,也就是将原服务名替换成服务所在的某一台机器ip和端口,替换之后就交由子类实现的exceut方法来发送blog.csdn.net/u010342147/article/details/123669493

如何解析Feign在RPC调用中结合Ribbon负载均衡的源码实现?

  blog.csdn.net/weixin_45630885/article/details/124391934

  blog.csdn.net/weixin_45630885/article/details/124533413