源码解析: Feign MethodHandler

2018-01-03  本文已影响0人  lazyguy

作用

MethodHandler从字面意思理解这是个方法管理器

 /**
   * Like {@link InvocationHandler#invoke(Object, java.lang.reflect.Method, Object[])}, except for a
   * single method.
   */
  interface MethodHandler {

    Object invoke(Object[] argv) throws Throwable;
  }

如注释所言,如果熟悉java.lang.reflect.InvocationHandler#invoke。大概就能明白。这是为了执行一个方法而预备的组件。
那么里面就应该包含了我们通过执行HTTP请求从而完成一个预定义的方法的逻辑。

SynchronousMethodHandler

这个类是Feign对MethodHandler的默认实现。参数太多,多以通过Factory工厂类去创建。

    Factory(Client client, Retryer retryer, List<RequestInterceptor> requestInterceptors,
            Logger logger, Logger.Level logLevel, boolean decode404) {
      this.client = checkNotNull(client, "client");
      this.retryer = checkNotNull(retryer, "retryer");
      this.requestInterceptors = checkNotNull(requestInterceptors, "requestInterceptors");
      this.logger = checkNotNull(logger, "logger");
      this.logLevel = checkNotNull(logLevel, "logLevel");
      this.decode404 = decode404;
    }

这里需要为其提供6个属性,既图中红色部分的组件。大致能猜出它们的作用。

  1. Client
    代表的是真正去执行HTTP请求的组件。他可以是OkHttpClient,也可以是Apache的HttpClient。草草观察Feign的默认实现Client.Default类可以看出其逻辑就是通过传入的Request相关参数,打开一个HttpURLConnection,执行完毕后,转换结果为Response对象,关闭连接。
  2. Retryer
    当我们的http请求通过client执行后,如果出现RetryableException。
    由Retryer这个组件负责决定是否按规定逻辑重新执行,或者抛出异常,中断执行。
    因为每个客户端发起的HTTP请求执行的情况各个不同,所以我们必须为每一个的http请求单独生成一个Retryer的实例,保存相关信息。这里使用了Clone,实现原型模式。
  3. RequestInterceptor
    为每个请求执行前加入拦截器的逻辑
  4. Logger
    Logger虚类自己实现了如下几个方法,你可以从名字和代码知道他们大概是在什么时候会被调用,用来记录日志。
    logRequest
    logRetry
    logAndRebufferResponse
    logIOException
    另外留下了一个log方法给子类自己去实现记录日志的场景逻辑。
  5. decode404
    这是个布尔值,是否反编码404?如果没看使用说明你也能猜到对于执行HTTP请求后得到404的情况,Feign提供了特殊的选项,其实就是就是抛出异常还是返回null的区别。

总结以上几个组件的作用。他们在一起的作用是“执行HTTP请求”。所以我们传给SynchronousMethodHandler.Factory的改造参数是告诉怎么去“执行HTTP请求”。

invoke方法

这个invoke方法就是我们真正调用某个接口的某个方法的时候,去执行的完整逻辑,只不过最后这个逻辑会被嵌入动态代理生成的类中而已。准备这个方法所需要的组件简直就是山路十八弯,但是这些组件最后被使用,就这么点 代码……

@Override
  public Object invoke(Object[] argv) throws Throwable {
    //这个RequestTemplate可以在每次调用时创建一个Request。
    RequestTemplate template = buildTemplateFromArgs.create(argv);
    //Retryer对于每次调用都需要一个单独的重试计数器。
    Retryer retryer = this.retryer.clone();
    while (true) {
      try {
        return executeAndDecode(template);
      } catch (RetryableException e) {
        retryer.continueOrPropagate(e);
        if (logLevel != Logger.Level.NONE) {
          logger.logRetry(metadata.configKey(), logLevel);
        }
        continue;
      }
    }
  }
Object executeAndDecode(RequestTemplate template) throws Throwable {
    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 10
      response.toBuilder().request(request).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);

    boolean shouldClose = true;
    try {
      if (logLevel != Logger.Level.NONE) {
        response =
            logger.logAndRebufferResponse(metadata.configKey(), logLevel, response, elapsedTime);
        // ensure the request is set. TODO: remove in Feign 10
        response.toBuilder().request(request).build();
      }
      if (Response.class == metadata.returnType()) {
        if (response.body() == null) {
          return response;
        }
        if (response.body().length() == null ||
                response.body().length() > MAX_RESPONSE_BUFFER_SIZE) {
          shouldClose = false;
          return response;
        }
        // Ensure the response body is disconnected
        byte[] bodyData = Util.toByteArray(response.body().asInputStream());
        return response.toBuilder().body(bodyData).build();
      }
      if (response.status() >= 200 && response.status() < 300) {
        if (void.class == metadata.returnType()) {
          return null;
        } else {
          return decode(response);
        }
      } else if (decode404 && response.status() == 404 && void.class != metadata.returnType()) {
        return decode(response);
      } else {
        throw errorDecoder.decode(metadata.configKey(), response);
      }
    } catch (IOException e) {
      if (logLevel != Logger.Level.NONE) {
        logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime);
      }
      throw errorReading(request, response, e);
    } finally {
      if (shouldClose) {
        ensureClosed(response.body());
      }
    }
  }
上一篇下一篇

猜你喜欢

热点阅读