spring boot open feign 客户端调用过程

读这篇文章之前请先看下这几篇文章
spring boot consul 客户端加载过程
spring boot Open Feign 客户端加载过程

读完上面的文章后我们知道
1,Cosnul客户端加载过程比OpenFeign晚,所以你想在OpenFeign加载完就发起请求是不可能的
2,OpenFeign依赖Consul,和 Load Balancer
3,OpenFeign真正发起请求是通过Java动态代理完成的

先回忆一下
OpenFeign动态代理生成对象的代码的ReflectiveFeign
这里用到了一个InvocationHandler 就是它自己的内部类
FeignInvocationHandler

public class ReflectiveFeign extends Feign { 
    private final SynchronousMethodHandler.Factory factory;

  @Override
  public  T newInstance(Target target) {
    Map nameToHandler = targetToHandlersByName.apply(target);
    Map methodToHandler = new LinkedHashMap();
    List defaultMethodHandlers = new LinkedList();

    for (Method method : target.type().getMethods()) {
      if (method.getDeclaringClass() == Object.class) {
        continue;
      } else if (Util.isDefault(method)) {
        DefaultMethodHandler handler = new DefaultMethodHandler(method);
        defaultMethodHandlers.add(handler);
        methodToHandler.put(method, handler);
      } else {
        methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
      }
    }
    InvocationHandler handler = factory.create(target, methodToHandler);
    T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
        new Class[] {target.type()}, handler);

    for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
      defaultMethodHandler.bindTo(proxy);
    }
    return proxy;
  }

  static class FeignInvocationHandler implements InvocationHandler {

    private final Target target;
    private final Map dispatch;

    FeignInvocationHandler(Target target, Map dispatch) {
      this.target = checkNotNull(target, "target");
      this.dispatch = checkNotNull(dispatch, "dispatch for %s", target);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
     。。。

      return dispatch.get(method).invoke(args);
    }
  }

  static final class ParseHandlersByName {

    private final Contract contract;
    private final Options options;
    private final Encoder encoder;
    private final Decoder decoder;
    private final ErrorDecoder errorDecoder;
    private final QueryMapEncoder queryMapEncoder;
    private final SynchronousMethodHandler.Factory factory;

    ParseHandlersByName(
        Contract contract,
        Options options,
        Encoder encoder,
        Decoder decoder,
        QueryMapEncoder queryMapEncoder,
        ErrorDecoder errorDecoder,
        SynchronousMethodHandler.Factory factory) {
      。。。
    }

    public Map apply(Target target) {
      List metadata = contract.parseAndValidateMetadata(target.type());
      Map result = new LinkedHashMap();
      for (MethodMetadata md : metadata) {
        BuildTemplateByResolvingArgs buildTemplate;
        if (!md.formParams().isEmpty() && md.template().bodyTemplate() == null) {
          buildTemplate =
              new BuildFormEncodedTemplateFromArgs(md, encoder, queryMapEncoder, target);
        } else if (md.bodyIndex() != null) {
          buildTemplate = new BuildEncodedTemplateFromArgs(md, encoder, queryMapEncoder, target);
        } else {
          buildTemplate = new BuildTemplateByResolvingArgs(md, queryMapEncoder, target);
        }
        if (md.isIgnored()) {
          result.put(md.configKey(), args -> {
            throw new IllegalStateException(md.configKey() + " is not a method handled by feign");
          });
        } else {
          result.put(md.configKey(),
              factory.create(target, md, buildTemplate, options, decoder, errorDecoder));
        }
      }
      return result;
    }
  }
}

我们看到的真正调用的是dispatch里的MethodHandler的invoke

也就是
ParseHandlersByName
它构建了 buidTemplate
然后通过SynchronousMethodHandler.Factory.create 创建MethodHandler

SynchronousMethodHandler

final class SynchronousMethodHandler implements MethodHandler {

  。。。
  

  private SynchronousMethodHandler(Target target, Client client, Retryer retryer,
      List requestInterceptors, Logger logger,
      Logger.Level logLevel, MethodMetadata metadata,
      RequestTemplate.Factory buildTemplateFromArgs, Options options,
      Decoder decoder, ErrorDecoder errorDecoder, boolean decode404,
      boolean closeAfterDecode, ExceptionPropagationPolicy propagationPolicy,
      boolean forceDecoding) {

    。。。
  }

  @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) {
          。。。
      }
    }
  }

  Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
    Request request = targetRequest(template);
。。。

    Response response;
    long start = System.nanoTime();
    try {
      // 用client发送请求
      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) {
      。。。
    }
       。。。
  }

  static class Factory {
    。。。
    Factory(。。。) {
        。。。
    }

    public MethodHandler create(。。。) {
      return new SynchronousMethodHandler(。。。);
    }
  }
}

Factory 工程类就不说明了

// 用client发送请求

response = client.execute(request, options);

这个client在
spring boot Open Feign 客户端加载过程
说明过

RetryableFeignBlockingLoadBalancerClient

public class RetryableFeignBlockingLoadBalancerClient implements Client {

    private static final Log LOG = LogFactory.getLog(FeignBlockingLoadBalancerClient.class);

    private final Client delegate;

    private final LoadBalancerClient loadBalancerClient;

    private final LoadBalancedRetryFactory loadBalancedRetryFactory;

    private final LoadBalancerProperties properties;

    private final LoadBalancerClientFactory loadBalancerClientFactory;

    public RetryableFeignBlockingLoadBalancerClient(Client delegate, LoadBalancerClient loadBalancerClient,
            LoadBalancedRetryFactory loadBalancedRetryFactory, LoadBalancerProperties properties,
            LoadBalancerClientFactory loadBalancerClientFactory) {
        this.delegate = delegate;
        this.loadBalancerClient = loadBalancerClient;
        this.loadBalancedRetryFactory = loadBalancedRetryFactory;
        this.properties = properties;
        this.loadBalancerClientFactory = loadBalancerClientFactory;
    }

    @Override
    public Response execute(Request request, Request.Options options) throws IOException {
        final URI originalUri = URI.create(request.url());
        String serviceId = originalUri.getHost();
        Assert.state(serviceId != null, "Request URI does not contain a valid hostname: " + originalUri);
        final LoadBalancedRetryPolicy retryPolicy = loadBalancedRetryFactory.createRetryPolicy(serviceId,
                loadBalancerClient);
        RetryTemplate retryTemplate = buildRetryTemplate(serviceId, request, retryPolicy);
        return retryTemplate.execute(context -> {
            Request feignRequest = null;
            ServiceInstance retrievedServiceInstance = null;
            Set supportedLifecycleProcessors = LoadBalancerLifecycleValidator
                    .getSupportedLifecycleProcessors(
                            loadBalancerClientFactory.getInstances(serviceId, LoadBalancerLifecycle.class),
                            RetryableRequestContext.class, ResponseData.class, ServiceInstance.class);
            String hint = getHint(serviceId);
            DefaultRequest lbRequest = new DefaultRequest<>(
                    new RetryableRequestContext(null, buildRequestData(request), hint));
            // On retries the policy will choose the server and set it in the context
            // and extract the server and update the request being made
            if (context instanceof LoadBalancedRetryContext) {
                LoadBalancedRetryContext lbContext = (LoadBalancedRetryContext) context;
                ServiceInstance serviceInstance = lbContext.getServiceInstance();
                if (serviceInstance == null) {
                    if (LOG.isDebugEnabled()) {
                        LOG.debug("Service instance retrieved from LoadBalancedRetryContext: was null. "
                                + "Reattempting service instance selection");
                    }
                    ServiceInstance previousServiceInstance = lbContext.getPreviousServiceInstance();
                    lbRequest.getContext().setPreviousServiceInstance(previousServiceInstance);
                    supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onStart(lbRequest));
                    retrievedServiceInstance = loadBalancerClient.choose(serviceId, lbRequest);
                    if (LOG.isDebugEnabled()) {
                        LOG.debug(String.format("Selected service instance: %s", retrievedServiceInstance));
                    }
                    lbContext.setServiceInstance(retrievedServiceInstance);
                }

                if (retrievedServiceInstance == null) {
                    if (LOG.isWarnEnabled()) {
                        LOG.warn("Service instance was not resolved, executing the original request");
                    }
                    org.springframework.cloud.client.loadbalancer.Response lbResponse = new DefaultResponse(
                            retrievedServiceInstance);
                    supportedLifecycleProcessors.forEach(lifecycle -> lifecycle
                            .onComplete(new CompletionContext(
                                    CompletionContext.Status.DISCARD, lbRequest, lbResponse)));
                    feignRequest = request;
                }
                else {
                    if (LOG.isDebugEnabled()) {
                        LOG.debug(String.format("Using service instance from LoadBalancedRetryContext: %s",
                                retrievedServiceInstance));
                    }
                    String reconstructedUrl = loadBalancerClient.reconstructURI(retrievedServiceInstance, originalUri)
                            .toString();
                    feignRequest = buildRequest(request, reconstructedUrl);
                }
            }
            org.springframework.cloud.client.loadbalancer.Response lbResponse = new DefaultResponse(
                    retrievedServiceInstance);
            Response response = LoadBalancerUtils.executeWithLoadBalancerLifecycleProcessing(delegate, options,
                    feignRequest, lbRequest, lbResponse, supportedLifecycleProcessors,
                    retrievedServiceInstance != null);
            int responseStatus = response.status();
            if (retryPolicy != null && retryPolicy.retryableStatusCode(responseStatus)) {
                if (LOG.isDebugEnabled()) {
                    LOG.debug(String.format("Retrying on status code: %d", responseStatus));
                }
                response.close();
                throw new RetryableStatusCodeException(serviceId, responseStatus, response, URI.create(request.url()));
            }
            return response;
        }, new LoadBalancedRecoveryCallback() {
            @Override
            protected Response createResponse(Response response, URI uri) {
                return response;
            }
        });
    }

    。。。

}

先看这句:根据serviceId从负载均衡中取得服务端信息
从注册中心取得服务端列表,根据某一算法找到一个合适的服务器信息

retrievedServiceInstance = loadBalancerClient.choose(serviceId, lbRequest);

然后这句

Response response = LoadBalancerUtils.executeWithLoadBalancerLifecycleProcessing(delegate, options,
                    feignRequest, lbRequest, lbResponse, supportedLifecycleProcessors,
                    retrievedServiceInstance != null);

LoadBalancerUtils

final class LoadBalancerUtils {

    private LoadBalancerUtils() {
        throw new IllegalStateException("Can't instantiate a utility class");
    }

    static Response executeWithLoadBalancerLifecycleProcessing(Client feignClient, Request.Options options,
            Request feignRequest, org.springframework.cloud.client.loadbalancer.Request lbRequest,
            org.springframework.cloud.client.loadbalancer.Response lbResponse,
            Set supportedLifecycleProcessors, boolean loadBalanced) throws IOException {
        supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onStartRequest(lbRequest, lbResponse));
        try {
            Response response = feignClient.execute(feignRequest, options);
            if (loadBalanced) {
                supportedLifecycleProcessors.forEach(
                        lifecycle -> lifecycle.onComplete(new CompletionContext<>(CompletionContext.Status.SUCCESS,
                                lbRequest, lbResponse, buildResponseData(response))));
            }
            return response;
        }
        catch (Exception exception) {
            if (loadBalanced) {
                supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onComplete(
                        new CompletionContext<>(CompletionContext.Status.FAILED, exception, lbRequest, lbResponse)));
            }
            throw exception;
        }
    }

    static ResponseData buildResponseData(Response response) {
        。。。
    }

    static RequestData buildRequestData(Request request) {
        。。。
    }

}

这里的feignClient是Client.Default
还是看:spring boot Open Feign 客户端加载过程
说明过

public interface Client {
  class Default implements Client {

    。。。

    @Override
    public Response execute(Request request, Options options) throws IOException {
      HttpURLConnection connection = convertAndSend(request, options);
      return convertResponse(connection, request);
    }

// 返回值不看
    Response convertResponse(HttpURLConnection connection, Request request) throws IOException {
      。。。
    }

    public HttpURLConnection getConnection(final URL url) throws IOException {
      return (HttpURLConnection) url.openConnection();
    }

    HttpURLConnection convertAndSend(Request request, Options options) throws IOException {
      final URL url = new URL(request.url());
      final HttpURLConnection connection = this.getConnection(url);
      。。。
      return connection;
    }
  }
}

代码很清楚:final URL url = new URL(request.url());
默认就是用Java底层的URL发送请求
至此,调用过程结束

接下来看下
loadBalancerClient

retrievedServiceInstance = loadBalancerClient.choose(serviceId, lbRequest);

请参照:spring boot loadbalancer 加载过程

你可能感兴趣的:(spring boot open feign 客户端调用过程)