Feign源码之调用流程

我们已经通过Feign源码之FeignClientFactoryBean创建动态代理知道了Feign的动态代理是怎么生成的了,那么现在就可以来看看feign是怎么来调用的

回归上篇文章的tager方法

public <T> T target(Target<T> target) {
      return build().newInstance(target);
    }

此时返回的是ReflectiveFeign的内部类对象FeignInvocationHandler,接下来就看看invoke方法是这么运作的

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);
    }

首先判断equals,hashCode和toString方法,如果是这几个,直接返回对应的方法,这三个方法都是委托给了成员变量target来调用具体的方法

public boolean equals(Object obj) {
            if (obj instanceof FeignInvocationHandler) {
                FeignInvocationHandler other = (FeignInvocationHandler) obj;
                return target.equals(other.target);
            }
            return false;
}

这里只看equals方法,他比较特殊,只有在传进来的obj对象是FeignInvocationHandler的时候才会继续调用target.equals(other.target)方法来进行比较,否则直接返回false

那么traget是何方神圣,其实已经在上文找到答案了,是HystrixTargeter对象,在FeignAutoConfiguration 中找到

@Configuration
@ConditionalOnMissingClass("feign.hystrix.HystrixFeign")
	protected static class DefaultFeignTargeterConfiguration {
		@Bean
		@ConditionalOnMissingBean
		public Targeter feignTargeter() {
			return new DefaultTargeter();
		}
	}

在newInstance方法中创建动态代理的时候

InvocationHandler handler = factory.create(target, methodToHandler);
public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) {
      return new ReflectiveFeign.FeignInvocationHandler(target, dispatch);
    }
FeignInvocationHandler(Target target, Map<Method, MethodHandler> dispatch) {
      this.target = checkNotNull(target, "target");
      this.dispatch = checkNotNull(dispatch, "dispatch for %s", target);
    }

接下来是如果不是equals,hashCode和toString方法,那么就从dispatch中获得当前方法的MethodHandler调用invoke方法来执行,这个MethodHandler就是上一文章中提到的SynchronousMethodHandler

dispatch.get(method).invoke(args)

查看SynchronousMethodHandler的invoke方法

public Object invoke(Object[] argv) throws Throwable {
    RequestTemplate template = buildTemplateFromArgs.create(argv);
    Retryer retryer = this.retryer.clone();
    while (true) {
      try {
        return executeAndDecode(template);
      } 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对象,然后调用executeAndDecode(template)方法:
进入executeAndDecode方法,看到client.execute(request, options);而这个client就是LoadBalancerFeignClient
继续查看execute方法

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);
		}
	}
  1. 首先获得URI和clientName
  2. 初始化ribbonRequest
  3. 获得requestConfig,如果options是默认的配置,则获取对应的ribbon配置(可以参考之前的ribbon系列文章了解更多),否则根据传进来的options初始化feign配置
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;
	}
  1. 获取lbClient,如果缓存中已经有了直接从缓存中获取,否则使用SpringClientFactory依次获得IClientConfig,ILoadBalancer,ServerIntrospector,最后根据loadBalancedRetryFactory是否存在容器中来决定初始化RetryableFeignLoadBalancer还是FeignLoadBalancer放入本地缓存中
public FeignLoadBalancer create(String clientName) {
		FeignLoadBalancer client = this.cache.get(clientName);
		if(client != null) {
			return client;
		}
		IClientConfig config = this.factory.getClientConfig(clientName);
		ILoadBalancer lb = this.factory.getLoadBalancer(clientName);
		ServerIntrospector serverIntrospector = this.factory.getInstance(clientName, ServerIntrospector.class);
		client = loadBalancedRetryFactory != null ? new RetryableFeignLoadBalancer(lb, config, serverIntrospector,
			loadBalancedRetryFactory) : new FeignLoadBalancer(lb, config, serverIntrospector);
		this.cache.put(clientName, client);
		return client;
	}

最后使用executeWithLoadBalancer方法来进行最终调用

public T executeWithLoadBalancer(final S request, final IClientConfig requestConfig) throws ClientException {
        LoadBalancerCommand<T> command = buildLoadBalancerCommand(request, requestConfig);

        try {
            return command.submit(
                new ServerOperation<T>() {
                    @Override
                    public Observable<T> call(Server server) {
                        URI finalUri = reconstructURIWithServer(server, request.getUri());
                        S requestForServer = (S) request.replaceUri(finalUri);
                        try {
                            return Observable.just(AbstractLoadBalancerAwareClient.this.execute(requestForServer, requestConfig));
                        } 
                        catch (Exception e) {
                            return Observable.error(e);
                        }
                    }
                })
                .toBlocking()
                .single();
        } catch (Exception e) {
            Throwable t = e.getCause();
            if (t instanceof ClientException) {
                throw (ClientException) t;
            } else {
                throw new ClientException(e);
            }
        }
        
    }

查看submit方法(这里开始大量使用了rxjava进行异步编程,暂不做讲解),获取maxRetrysSame和maxRetrysNext的信息

final int maxRetrysSame = retryHandler.getMaxRetriesOnSameServer();
        final int maxRetrysNext = retryHandler.getMaxRetriesOnNextServer();

根据负载均衡获取server

server == null ? selectServer() : Observable.just(server)

查看selectServer的方法

private Observable<Server> selectServer() {
        return Observable.create(new OnSubscribe<Server>() {
            @Override
            public void call(Subscriber<? super Server> next) {
                try {
                    Server server = loadBalancerContext.getServerFromLoadBalancer(loadBalancerURI, loadBalancerKey);   
                    next.onNext(server);
                    next.onCompleted();
                } catch (Exception e) {
                    next.onError(e);
                }
            }
        });
    }

看到了熟悉的loadBalancerContext,至此正式与之前的ribbon源码接轨,通过ribbon选择服务器
Feign源码之调用流程_第1张图片

最后就是拼接url来调用了

URI finalUri = reconstructURIWithServer(server, request.getUri());
                        S requestForServer = (S) request.replaceUri(finalUri);
                        try {
                            return Observable.just(AbstractLoadBalancerAwareClient.this.execute(requestForServer, requestConfig));
                        } 
                        catch (Exception e) {
                            return Observable.error(e);
                        }

推荐阅读
ribbon源码分析之自定义配置、全局配置
Ribbon源码之负载均衡器ILoadBalancer
ribbon源码之服务列表过滤器以及ZoneAwareLoadBalancer

你可能感兴趣的:(springClound,源码,微服务,java,微服务,开发语言)