首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Retrofit解析8之核心解析——ServiceMethod及注解1

Retrofit解析8之核心解析——ServiceMethod及注解1

作者头像
隔壁老李头
发布2018-08-30 11:49:58
1.9K0
发布2018-08-30 11:49:58
举报
文章被收录于专栏:Android 研究Android 研究

上篇文章已经介绍了Retrofit里面的大多数类,今天就重点介绍ServiceMethod,本片文章主要内容如下:

  • 1、ParameterHandler类
  • 2、ServiceMethod类
  • 3、Retrofit类

为了方便后面学习ServiceMethod,我们先来看下ParameterHandler类

一、ParameterHandler类

(一)、ParameterHandler类是什么?

从字面意思我们猜到 他是参数处理类。具体是不是那?用源码说话,看源码

abstract class ParameterHandler<T> {
  abstract void apply(RequestBuilder builder, T value) throws IOException;
  final ParameterHandler<Iterable<T>> iterable() {
    return new ParameterHandler<Iterable<T>>() {
      @Override void apply(RequestBuilder builder, Iterable<T> values) throws IOException {
        if (values == null) return; // Skip null values.
        for (T value : values) {
          ParameterHandler.this.apply(builder, value);
        }
      }
    };
  }
  final ParameterHandler<Object> array() {
    return new ParameterHandler<Object>() {
      @Override void apply(RequestBuilder builder, @Nullable Object values) throws IOException {
        if (values == null) return; // Skip null values.

        for (int i = 0, size = Array.getLength(values); i < size; i++) {
          //noinspection unchecked
          ParameterHandler.this.apply(builder, (T) Array.get(values, i));
        }
      }
    };
  }
  //由于篇幅的限制,我没有粘贴静态内部类
}

通过简单阅读源代码,我们得知:

  • ParameterHandler 是一个抽象类
  • 一共有3个方法,其中一个是抽象方法
  • apply(RequestBuilder builder, T value)方法是抽象的,需要子类去实现
  • iterable()方法返回的是new的一个ParameterHandler,不过的他的泛型是Iterable<T>,所以它的抽象方法的具体实现是遍历这个迭代器Iterable,调用这个对象的apply()方法,注意这个方法是final。
  • array()方法 返回的是一个new的一个ParameterHandler,它的泛型是Object,而他的抽象方法是通过遍历数组的方式来分别调用对应的apply()方法,这个方法也是final的

这里说下iterable()方法和array()方法,说明ParameterHandler是支持两种数据类型的处理方式。一个是对应迭代器(iterable)的类型;一个是对应的是数组类型的。所以我们继续往下看

(二)、静态内部类RelativeUrl

看下源码:

  static final class RelativeUrl extends ParameterHandler<Object> {
    @Override void apply(RequestBuilder builder, Object value) {
      builder.setRelativeUrl(value);
    }
  }

  • 首先,这个类是final的
  • 其次,貌似很简单,RelativeUrl类内部就是调用RequestBuilder的setRelativeUrl方法来设置RequestBuilder的relativeUrl的值
(三)、静态内部类Header

看下源码:

  static final class Header<T> extends ParameterHandler<T> {
    private final String name;
    private final Converter<T, String> valueConverter;
    Header(String name, Converter<T, String> valueConverter) {
      this.name = checkNotNull(name, "name == null");
      this.valueConverter = valueConverter;
    }
    @Override void apply(RequestBuilder builder, T value) throws IOException {
      if (value == null) return; // Skip null values.
      builder.addHeader(name, valueConverter.convert(value));
    }
  }

  • 首先这个类是final的
  • 其次这个类有两个final的变量,在构造的时候赋值
  • apply抽象方法也是调用RequestBuilder的addHeader方法给RequestBuilder的header赋值
  • apply里面有调用Converter的convert的方法把value进行转化,其实是序列化。
(四)、静态内部类Path

看下源码:

    private final String name;
    private final Converter<T, String> valueConverter;
    private final boolean encoded;

    Path(String name, Converter<T, String> valueConverter, boolean encoded) {
      this.name = checkNotNull(name, "name == null");
      this.valueConverter = valueConverter;
      this.encoded = encoded;
    }

    @Override void apply(RequestBuilder builder, T value) throws IOException {
      if (value == null) {
        throw new IllegalArgumentException(
            "Path parameter \"" + name + "\" value must not be null.");
      }
      builder.addPathParam(name, valueConverter.convert(value), encoded);
    }

  • 首先这个类是final的
  • 其次这个类有三个final的变量,在构造的时候赋值
  • apply抽象方法也是调用RequestBuilder的addPathParam方法进行设置
  • apply里面有调用Converter的convert的方法把value进行转化,其实是序列化。
(五)、静态内部类Query

看下源码:

  static final class Query<T> extends ParameterHandler<T> {
    private final String name;
    private final Converter<T, String> valueConverter;
    private final boolean encoded;

    Query(String name, Converter<T, String> valueConverter, boolean encoded) {
      this.name = checkNotNull(name, "name == null");
      this.valueConverter = valueConverter;
      this.encoded = encoded;
    }

    @Override void apply(RequestBuilder builder, T value) throws IOException {
      if (value == null) return; // Skip null values.
      builder.addQueryParam(name, valueConverter.convert(value), encoded);
    }
  }

  • 首先这个类是final的
  • 其次这个类有三个final的变量,在构造的时候赋值
  • apply抽象方法也是调用RequestBuilder的addQueryParam方法进行设置
  • apply里面有调用Converter的convert的方法把value进行转化,其实是序列化。
(六)、静态内部类QueryName

看下源码:

  static final class QueryName<T> extends ParameterHandler<T> {
    private final Converter<T, String> nameConverter;
    private final boolean encoded;
    QueryName(Converter<T, String> nameConverter, boolean encoded) {
      this.nameConverter = nameConverter;
      this.encoded = encoded;
    }
    @Override void apply(RequestBuilder builder, T value) throws IOException {
      if (value == null) return; // Skip null values.
      builder.addQueryParam(nameConverter.convert(value), null, encoded);
    }
  }

  • 首先这个类是final的
  • 其次这个类有二个final的变量,在构造的时候赋值
  • apply抽象方法也是调用RequestBuilder的addQueryParam方法进行设置
  • apply里面有调用Converter的convert的方法把value进行转化,其实是序列化。
(七)、静态内部类QueryMap

看下源码:

static final class QueryMap<T> extends ParameterHandler<Map<String, T>> {
    private final Converter<T, String> valueConverter;
    private final boolean encoded;

    QueryMap(Converter<T, String> valueConverter, boolean encoded) {
      this.valueConverter = valueConverter;
      this.encoded = encoded;
    }

    @Override void apply(RequestBuilder builder, Map<String, T> value) throws IOException {
      if (value == null) {
        throw new IllegalArgumentException("Query map was null.");
      }

      for (Map.Entry<String, T> entry : value.entrySet()) {
        String entryKey = entry.getKey();
        if (entryKey == null) {
          throw new IllegalArgumentException("Query map contained null key.");
        }
        T entryValue = entry.getValue();
        if (entryValue == null) {
          throw new IllegalArgumentException(
              "Query map contained null value for key '" + entryKey + "'.");
        }
        builder.addQueryParam(entryKey, valueConverter.convert(entryValue), encoded);
      }
    }
  }

  • 首先这个类是final的
  • 其次这个类有二个final的变量,在构造的时候赋值
  • apply抽象方法内部首先遍历Map,获取对应的key 和value,然后调用RequestBuilder的addQueryParam方法进行设置
  • apply里面有调用Converter的convert的方法把value进行转化,其实是序列化。
(八)、静态内部类HeaderMap

看下源码:

 static final class HeaderMap<T> extends ParameterHandler<Map<String, T>> {
    private final Converter<T, String> valueConverter;

    HeaderMap(Converter<T, String> valueConverter) {
      this.valueConverter = valueConverter;
    }

    @Override void apply(RequestBuilder builder, Map<String, T> value) throws IOException {
      if (value == null) {
        throw new IllegalArgumentException("Header map was null.");
      }

      for (Map.Entry<String, T> entry : value.entrySet()) {
        String headerName = entry.getKey();
        if (headerName == null) {
          throw new IllegalArgumentException("Header map contained null key.");
        }
        T headerValue = entry.getValue();
        if (headerValue == null) {
          throw new IllegalArgumentException(
              "Header map contained null value for key '" + headerName + "'.");
        }
        builder.addHeader(headerName, valueConverter.convert(headerValue));
      }
    }
  }

  • 首先这个类是final的
  • 其次这个类有一个final的变量,在构造的时候赋值
  • apply抽象方法内部首先遍历Map,获取对应的key 和value,然后调用RequestBuilder的addHeader方法进行设置
  • apply里面有调用Converter的convert的方法把value进行转化,其实是序列化。
(九)、静态内部类Field

看下源码:

static final class Field<T> extends ParameterHandler<T> {
    private final String name;
    private final Converter<T, String> valueConverter;
    private final boolean encoded;

    Field(String name, Converter<T, String> valueConverter, boolean encoded) {
      this.name = checkNotNull(name, "name == null");
      this.valueConverter = valueConverter;
      this.encoded = encoded;
    }

    @Override void apply(RequestBuilder builder, T value) throws IOException {
      if (value == null) return; // Skip null values.
      builder.addFormField(name, valueConverter.convert(value), encoded);
    }
  }

  • 首先这个类是final的
  • 其次这个类有三个final的变量,在构造的时候赋值
  • apply抽象方法内部调用RequestBuilder的addFormField方法进行设置
  • apply里面有调用Converter的convert的方法把value进行转化,其实是序列化。
(十)、静态内部类FieldMap

看下源码:

static final class FieldMap<T> extends ParameterHandler<Map<String, T>> {
    private final Converter<T, String> valueConverter;
    private final boolean encoded;

    FieldMap(Converter<T, String> valueConverter, boolean encoded) {
      this.valueConverter = valueConverter;
      this.encoded = encoded;
    }

    @Override void apply(RequestBuilder builder, Map<String, T> value) throws IOException {
      if (value == null) {
        throw new IllegalArgumentException("Field map was null.");
      }

      for (Map.Entry<String, T> entry : value.entrySet()) {
        String entryKey = entry.getKey();
        if (entryKey == null) {
          throw new IllegalArgumentException("Field map contained null key.");
        }
        T entryValue = entry.getValue();
        if (entryValue == null) {
          throw new IllegalArgumentException(
              "Field map contained null value for key '" + entryKey + "'.");
        }
        builder.addFormField(entryKey, valueConverter.convert(entryValue), encoded);
      }
    }
  }

  • 首先这个类是final的
  • 其次这个类有二个final的变量,在构造的时候赋值
  • apply抽象方法内部首先遍历Map,获取对应的key 和value,然后调用RequestBuilder的addFormField方法进行设置
  • apply里面有调用Converter的convert的方法把value进行转化,其实是序列化。
(十一)、静态内部类Part

看下源码:

static final class Part<T> extends ParameterHandler<T> {
    private final Headers headers;
    private final Converter<T, RequestBody> converter;

    Part(Headers headers, Converter<T, RequestBody> converter) {
      this.headers = headers;
      this.converter = converter;
    }

    @Override void apply(RequestBuilder builder, T value) {
      if (value == null) return; // Skip null values.

      RequestBody body;
      try {
        body = converter.convert(value);
      } catch (IOException e) {
        throw new RuntimeException("Unable to convert " + value + " to RequestBody", e);
      }
      builder.addPart(headers, body);
    }
  }

  • 首先这个类是final的
  • 其次这个类有二个final的变量,在构造的时候赋值
  • apply抽象方法内部首先通过convert的方法把value进行转化(其实是序列化),然后调用RequestBuilder的addPart方法进行设置。
(十二)、静态内部类RawPart

看下源码:

static final RawPart INSTANCE = new RawPart();

    private RawPart() {
    }

    @Override void apply(RequestBuilder builder, MultipartBody.Part value) throws IOException {
      if (value != null) { // Skip null values.
        builder.addPart(value);
      }
    }

  • 首先这个类是final的
  • 其次这个类构造函数是私有的,并且定义了一个静态的常量对象,所以这个是类的对象是单例模式。
  • apply抽象方法调用RequestBuilder的addPart方法进行设置。
(十三)、静态内部类PartMap

看下源码:

  static final class PartMap<T> extends ParameterHandler<Map<String, T>> {
    private final Converter<T, RequestBody> valueConverter;
    private final String transferEncoding;

    PartMap(Converter<T, RequestBody> valueConverter, String transferEncoding) {
      this.valueConverter = valueConverter;
      this.transferEncoding = transferEncoding;
    }

    @Override void apply(RequestBuilder builder, Map<String, T> value) throws IOException {
      if (value == null) {
        throw new IllegalArgumentException("Part map was null.");
      }

      for (Map.Entry<String, T> entry : value.entrySet()) {
        String entryKey = entry.getKey();
        if (entryKey == null) {
          throw new IllegalArgumentException("Part map contained null key.");
        }
        T entryValue = entry.getValue();
        if (entryValue == null) {
          throw new IllegalArgumentException(
              "Part map contained null value for key '" + entryKey + "'.");
        }

        Headers headers = Headers.of(
            "Content-Disposition", "form-data; name=\"" + entryKey + "\"",
            "Content-Transfer-Encoding", transferEncoding);

        builder.addPart(headers, valueConverter.convert(entryValue));
      }
    }
  }

  • 首先这个类是final的
  • 其次这个类有二个final的变量,在构造的时候赋值
  • apply抽象方法内部首先遍历Map,获取对应的key 和value,然后调用okhttp3的Headers.of()方法添加headers,最后调用RequestBuilder的addPart方法进行设置
  • apply里面有调用Converter的convert的方法把value进行转化,其实是序列化。
(十四)、静态内部类Body

看下源码:

   static final class Body<T> extends ParameterHandler<T> {
    private final Converter<T, RequestBody> converter;

    Body(Converter<T, RequestBody> converter) {
      this.converter = converter;
    }

    @Override void apply(RequestBuilder builder, T value) {
      if (value == null) {
        throw new IllegalArgumentException("Body parameter value must not be null.");
      }
      RequestBody body;
      try {
        body = converter.convert(value);
      } catch (IOException e) {
        throw new RuntimeException("Unable to convert " + value + " to RequestBody", e);
      }
      builder.setBody(body);
    }
  }

  • 首先这个类是final的
  • 其次这个类有一个final的变量,在构造的时候赋值
  • apply抽象方法内部首先调用Converter的convert的方法把value进行转化,其实就是序列化。然后调用RequestBuilder的setBody方法进行设置
(十五)、总结

本来这篇内容应该放到上一篇文章中,但是由于受到篇幅限制的原由,所以放到这里了,看完ParameterHandler类的源码在回想下ParameterHandler的源码,大家有没有想到一些东西?

其实Retrofit团队是这样分工的,RequestBuilder仅仅是一个包装类,但是具体的赋值操作等其实是通过ParameterHandler对应的静态内部类来实现的,这样实现了包装和操作分离,实现了解耦。多么"优雅"的设计。

二、ServiceMethod类

(一)、ServiceMethod类是什么?

首先用类注解解释下ServiceMethod是什么?

/** Adapts an invocation of an interface method into an HTTP call. */

我翻译一下:

将一个接口的方方法的调用适配成一个HTTP的Call。

我的理解是:

ServiceMethod是一个负责转化(适配)的类,负责把一个接口的抽象方法的执行过程的结果转化(适配)成一个网络请求(HTTP call)。

ok 那我们来看下他的源码

(二)、ServiceMethod类源码

由于这个类略大,一直在纠结要不要把全部代码粘贴上,但是考虑到大家的情况,还是粘贴了,不过省略了Buidler内部静态类的代码,希望大家理解。

1、ServiceMethod源码:
/** Adapts an invocation of an interface method into an HTTP call. */
final class ServiceMethod<R, T> {
  // Upper and lower characters, digits, underscores, and hyphens, starting with a character.
  static final String PARAM = "[a-zA-Z][a-zA-Z0-9_-]*";
  static final Pattern PARAM_URL_REGEX = Pattern.compile("\\{(" + PARAM + ")\\}");
  static final Pattern PARAM_NAME_REGEX = Pattern.compile(PARAM);

  final okhttp3.Call.Factory callFactory;
  final CallAdapter<R, T> callAdapter;

  private final HttpUrl baseUrl;
  private final Converter<ResponseBody, R> responseConverter;
  private final String httpMethod;
  private final String relativeUrl;
  private final Headers headers;
  private final MediaType contentType;
  private final boolean hasBody;
  private final boolean isFormEncoded;
  private final boolean isMultipart;
  private final ParameterHandler<?>[] parameterHandlers;

  ServiceMethod(Builder<R, T> builder) {
    this.callFactory = builder.retrofit.callFactory();
    this.callAdapter = builder.callAdapter;
    this.baseUrl = builder.retrofit.baseUrl();
    this.responseConverter = builder.responseConverter;
    this.httpMethod = builder.httpMethod;
    this.relativeUrl = builder.relativeUrl;
    this.headers = builder.headers;
    this.contentType = builder.contentType;
    this.hasBody = builder.hasBody;
    this.isFormEncoded = builder.isFormEncoded;
    this.isMultipart = builder.isMultipart;
    this.parameterHandlers = builder.parameterHandlers;
  }

  /** Builds an HTTP request from method arguments. */
  Request toRequest(Object... args) throws IOException {
    RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
        contentType, hasBody, isFormEncoded, isMultipart);

    @SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
    ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;

    int argumentCount = args != null ? args.length : 0;
    if (argumentCount != handlers.length) {
      throw new IllegalArgumentException("Argument count (" + argumentCount
          + ") doesn't match expected count (" + handlers.length + ")");
    }

    for (int p = 0; p < argumentCount; p++) {
      handlers[p].apply(requestBuilder, args[p]);
    }

    return requestBuilder.build();
  }

  /** Builds a method return value from an HTTP response body. */
  R toResponse(ResponseBody body) throws IOException {
    return responseConverter.convert(body);
  }
  //省略了Builder内部类
}

通过错略看过源代码可以获取如下信息:

  • ServiceMethod是final的,不能被继承
  • ServiceMethod的构造函数既不是public,也是private的,所以只能在包内创建ServiceMethod对象。
  • ServiceMethod有一个静态内部类Builder。是final的,同样不能被继承,看到Builder,大家一定知道了ServiceMethod是Builder模式,所以 ServiceMethod构造函数就一个入参是Builder
  • 所有的变量均是final的
  • 一共有4个方法,两个静态的两个非静态的
  • boxIfPrimitive (Class<?> type) 静态方法:明显就是获取8个基本类型对应的装箱类
  • parsePathParameters (String path) 静态方法: 保证url中的路径参数(PathParameters)有且仅使用一次,不会出现重复的路径参数(PathParameters)。
2、源码详解:
2.1、变量解析:

大家先来看下变量,由于变量不多,我直接上注释了。

 //用来校验的常量
static final String PARAM = "[a-zA-Z][a-zA-Z0-9_-]*";
  static final Pattern PARAM_URL_REGEX = Pattern.compile("\\{(" + PARAM + ")\\}");
  static final Pattern PARAM_NAME_REGEX = Pattern.compile(PARAM);
  //网络请求call的工厂,注释是okhttp3的
  final okhttp3.Call.Factory callFactory;
  // 网络请求适配器
  final CallAdapter<R, T> callAdapter;
  //基础HttpUrl
  private final HttpUrl baseUrl;
  //响应转化器
  private final Converter<ResponseBody, R> responseConverter;
   //网络请求的方法
  private final String httpMethod;
  //网络请求url的相对路径
  private final String relativeUrl;
  // 请求头
  private final Headers headers;
   //请求类型
  private final MediaType contentType;
  //是否有请求体
  private final boolean hasBody;
  //是否是表单提交
  private final boolean isFormEncoded;
  //以二进制流的方式提交
  private final boolean isMultipart;
  //参数处理器。具体在后面讲解
  private final ParameterHandler<?>[] parameterHandlers;
2.2、ServiceMethod的两个非静态方法:
2.2.1首先来看下toRequest方法
  /** Builds an HTTP request from method arguments. */
  Request toRequest(Object... args) throws IOException {
    //new 了一个RequestBuilder对象
    RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
        contentType, hasBody, isFormEncoded, isMultipart);
    @SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
    ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
    //获取入参的个数
    int argumentCount = args != null ? args.length : 0;
    if (argumentCount != handlers.length) {
      throw new IllegalArgumentException("Argument count (" + argumentCount
          + ") doesn't match expected count (" + handlers.length + ")");
    }
    //遍历入参
    for (int p = 0; p < argumentCount; p++) {
      //配置对应的requestBuilder属性
      handlers[p].apply(requestBuilder, args[p]);
    }
    //调用requestBuilder的build()方法获取一个okhttp3.request对象
    return requestBuilder.build();
  }

通过注释我们发现,其实这个方法是:

通过方法的入参来够将一个HTTP的请求。

方法内的大体流程如下:

  • 1、new 了一个RequestBuilder对象
  • 2、 获取入参的个数,并与自身对应的入参处理类的个数进行对比,不一致抛异常,理论上应该是一致的,因为你的每个“方法”的每一个入参都对应一个注解。
  • 3、遍历这些入参处理类,开始配置requestBuilder属性
  • 4、配置完毕,调用requestBuilder的.build()方法获取一个okhttp3.Request对象
2.2.2 让我们来看下toResponse方法
  /** Builds a method return value from an HTTP response body. */
  R toResponse(ResponseBody body) throws IOException {
    return responseConverter.convert(body);
  }

通过方法注释我们得知:

通过一个HTTP的响应体(response body)来构建一个方法的返回值。

方法很简单就一行,就是调用响应解析/处理器(responseConverter)的convert方法来解析/反序列化响应体。

3、静态内部类 ServiceMethod.Builder
3.1、先看下类的注释
  /**
   * Inspects the annotations on an interface method to construct a reusable service method. This
   * requires potentially-expensive reflection so it is best to build each service method only once
   * and reuse it. Builders cannot be reused.
   */

翻译一下就是

通过检查接口方法上的注解来构建一个可以重用的 "服务方法",由于用到高性能消耗的反射,所以最好一个 "服务方法" 只构建一次,并且可以重复使用。Builders不能被重用

我的理解是:

其实Retrofit内部是通过动态代理,内部是通过反射实现的,大家都知道反射其实是很消耗性能的,为了避免这种高性能的消耗,反射成功以后就缓存起来,下次如果有用到就重用,如果不能重用则用反射构建出来,但是Builder是不能重用的。

3.2、 ServiceMethod.Builder源码解析

由于Builder源码太多了,我就不上源码了 我们来看下Builder类的变量,我直接标注释了

3.2.1、ServiceMethod.Builder变量解析
    //Retrofit
    final Retrofit retrofit;
    //定义接口的抽象方法
    final Method method;
    //定义接口的抽象方法上面的注解数组
    final Annotation[] methodAnnotations;
     //注解二维数组:第一维对应参数序列,第二维对应注解序列;
    final Annotation[][] parameterAnnotationsArray;
     // 参数类型数组
    final Type[] parameterTypes;
    // 响应的类型
    Type responseType;
    //是否有用 @Field 或者FieldMap 注解
    boolean gotField;
     //是否 有用@Part 或者 @PartMap注解
    boolean gotPart;
    //是否有用 @body注解
    boolean gotBody;
     // 是否 有用@Path 注解
    boolean gotPath;
     //是否 有用@Query 或者@QueryName 注解
    boolean gotQuery;
     // 是否具有url
    boolean gotUrl;
     //http 请求的方法
    String httpMethod;
     //是否  需要请求体
    boolean hasBody;
    //是否 使用@FormUrlEncoded  注解
    boolean isFormEncoded;
    // 是否 使用了@Multipart  注解
    boolean isMultipart;
    // 相对路径
    String relativeUrl;
     //请求头
    Headers headers;
    //类型
    MediaType contentType;
     //相对路径的url参数
    Set<String> relativeUrlParamNames;
     //参数处理数组
    ParameterHandler<?>[] parameterHandlers;
     //响应转化器
    Converter<ResponseBody, T> responseConverter;
     //请求转化器
    CallAdapter<T, R> callAdapter;
3.2.2、 Builder构造函数解析
    Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      this.methodAnnotations = method.getAnnotations();
      this.parameterTypes = method.getGenericParameterTypes();
      this.parameterAnnotationsArray = method.getParameterAnnotations();
    }

  • 我们知道Builder的构造函数有两个入参,一个是Retrofit对象本身,一个是Method 对象。
  • methodAnnotations、parameterTypes、parameterAnnotationsArray这三个变量的值都是通过method的三个方法获取的
PS:通过之前反射的学习我们知道Method.getAnnotations(); 是获取方法上面对应的注解。method.getGenericParameterTypes();获取的是方法参数的类型,里面带有实际的参数类型。method.getParameterAnnotations();获取的是方法参数上面的注解,是一个二维数组,第一个维度代表的是方法参数对应的下标,比如,一个方法有3个参数,那0代表第一个参数,1代表第二个参数,2代表第三个参数。

通过构造函数我们知道Builder类里面的5个变量已经被初始化了

3.2.3、 Builder的方法build()方法解析
public ServiceMethod build() {
      //通过调用createCallAdapter()方法获取callAdapter
      callAdapter = createCallAdapter();
      //通过调用callAdapter的responseType方法获取响应体类型
      responseType = callAdapter.responseType();
      if (responseType == Response.class || responseType == okhttp3.Response.class) {
        throw methodError("'"
            + Utils.getRawType(responseType).getName()
            + "' is not a valid response body type. Did you mean ResponseBody?");
      }
      //通过createResponseConverter()方法获取响应转化器
      responseConverter = createResponseConverter();
      //遍历方法的注解
      for (Annotation annotation : methodAnnotations) {
        //解析方法注解
        parseMethodAnnotation(annotation);
      }
      //如果没有HTTP请求的方法,则抛异常
      if (httpMethod == null) {
        throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
      }
      //在上面遍历方法注解并解析方法注解的时候,hasBody,isMultipart,isFormEncoded等已经完成赋值
      //如果没有请求体
      if (!hasBody) {
         //但是 还是使用了@Multipart注解,使用了@Multipart 是一定有消息体的
        if (isMultipart) {
          throw methodError(
              "Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
        }
         //但是 还是使用了 @FormEncoded,使用了@FormEncoded 是一定有消息体的
        if (isFormEncoded) {
          throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
              + "request body (e.g., @POST).");
        }
      }
      //如果方法 入参的注解,它的长度也就是有多少个入参,遍历每个入参对应的注解
      int parameterCount = parameterAnnotationsArray.length;
      //创建对应的数量的参数处理类数组,这时候开始处理入参对应的注解了
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      //遍历入参的数量
      for (int p = 0; p < parameterCount; p++) {
         //首先获取入参的类型
        Type parameterType = parameterTypes[p];
         //如果是不能处理的类型,则抛异常
        if (Utils.hasUnresolvableType(parameterType)) {
          throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
              parameterType);
        }
        //如果是可以处理的类型获取对应位置入参的注解
        Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
        //如果对应入参的注解为null,则抛异常
        if (parameterAnnotations == null) {
          throw parameterError(p, "No Retrofit annotation found.");
        }
         //如果对应的入参注解不为null,则调用parseParameter方法获取ParameterHandler,cancel在这里方法里面创建ParameterHandler里面的静态内部类,后面咱们再仔细看下。
        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
      }
       //for循环遍历以后,如果relativeUrl还为null,同时没有使用!@url注解,这样的话我们就无法获取url地址了,所以要抛异常。
      if (relativeUrl == null && !gotUrl) {
        throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
      }
      //如果没有使用@FormEncoded注解、@Multipart和,同时HTTP请求方式也不需要响应提,但是却使用了@Body 注解,这不是自相矛盾,所以抛异常。
      if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
        throw methodError("Non-body HTTP method cannot contain @Body.");
      }
      //如果使用@FormEncoded注解,却没使用@Field注解,不符合规范,则抛异常
      if (isFormEncoded && !gotField) {
        throw methodError("Form-encoded method must contain at least one @Field.");
      }
      //如果使用 @Multipart 注解,却没有使用@Part 注解,抛异常
      if (isMultipart && !gotPart) {
        throw methodError("Multipart method must contain at least one @Part.");
      }
      //走到这里说明没有问题,则new一个ServiceMethod对象,入参是Builder自己,然后return这个ServiceMethod对象。
      return new ServiceMethod<>(this);
    }

大体流程如下:

  • 1、通过createCallAdapter()方法取得callAdapter对象
  • 2、通过callAdapter的responseType()方法获取响应对应的类型
  • 3、通过createResponseConverter()来获取响应转化/解析器
  • 4、遍历方法上的注解,并解析注解
  • 5、判断是GET还是POST或者其他HTTP请求方式
  • 6、异常逻辑判断,如果HTTP请求方式不需要消息体,但是却使用@FormEncoded注解、@Multipart,自相矛盾。
  • 7、获取这个方法入参的个数
  • 8、遍历这个方法的各个入参,首先判断是不是能处理的类型,如果是能处理的类型;然后获取这个入参对应的注解;最后调用parseParameter()来获取对应的parameterHandlers。
  • 9、异常逻辑判断,比如如果没有相对路径还没有使用@Url,我们会无法得到具体的地址。
  • 10、异常逻辑处理,既没有使用@FormUrlEncode 注解也没有使用@Multipart注解,且HTTP请求方式也需要使用请求,却使用@Body 注解,违反规范,抛异常
  • 11、异常逻辑处理,使用@FormUrlEncoded注解,但是却没有使用@Field注解,这是违背Retrofit的规定的。
  • 12、异常逻辑处理,使用了@Multipart 注解,却没有使用@Part注解,同样是违背Retrofit的规定的。
  • 13、最后new了一个ServiceMethod对象,并return

自此整个build流程已经全部解析完毕,那我们在看来里面设计的其它方法

3.2.4、 Builder的方法createCallAdapter解析

通过方法字面的含义我们理解为这个方法创建CallAdatper,具体我们看下源码:

    private CallAdapter<T, R> createCallAdapter() {
       //获取方法的返回值类型
      Type returnType = method.getGenericReturnType();
       //如果方法的返回值类型我们无法处理,则抛出异常
      if (Utils.hasUnresolvableType(returnType)) {
        throw methodError(
            "Method return type must not include a type variable or wildcard: %s", returnType);
      }
      //如果方法是void的,则没有返回值
      if (returnType == void.class) {
        throw methodError("Service methods cannot return void.");
      }
      //获取方法的注解
      Annotation[] annotations = method.getAnnotations();
      try {
        //调用retrofit的callAdapter来获取一个CallAdapter对象
        //noinspection unchecked
        return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
      } catch (RuntimeException e) { // Wide exception range because factories are user code.
        throw methodError(e, "Unable to create call adapter for %s", returnType);
      }
    }

大体流程如下:

  • 1、通过method.getGenericReturnType()获取返回值类型
  • 2、排除我们不能处理的类型
  • 3、排除无返回值(void)的情况
  • 4、调用 retrofit的callAdapter的方法来获取一个CallAdapter对象,这个里面的内部调用,我们一会再说。
3.2.5、 Builder的方法parseMethodAnnotation解析

这个方法看字面的意思就知道是一个处理方法的注解,具体以源码为准。

 private void parseMethodAnnotation(Annotation annotation) {
      //如果是DELETE注解 代表DELETE请求
      if (annotation instanceof DELETE) {
         //调用parseHttpMethodAndPath()
        parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
        //如果是GET 注解,则代表是get请求
      } else if (annotation instanceof GET) {
       //调用parseHttpMethodAndPath()
        parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
        //如果是 HEAD注解,则代表HEAD请求,这里不是请求头,HEAD方法跟GET方法相同,只不过服务器响应时不会返回消息体。
      } else if (annotation instanceof HEAD) {
          //调用parseHttpMethodAndPath()
        parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
        if (!Void.class.equals(responseType)) {
           //HEAD请求是没有响应体的
          throw methodError("HEAD method must use Void as response type.");
        }
        //如果是PATCH请求
      } else if (annotation instanceof PATCH) {
          //调用parseHttpMethodAndPath()
        parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
      } else if (annotation instanceof POST) {
        //调用parseHttpMethodAndPath()
        parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
       //如果是PUT请求
      } else if (annotation instanceof PUT) {
        //调用parseHttpMethodAndPath()
        parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
         //如果是 OPTIONS注解,代表OPTIONS请求
      } else if (annotation instanceof OPTIONS) {
          //调用parseHttpMethodAndPath()
        parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
          //如果是@HTTP 注解,则代表自定义 HTTP请求
      } else if (annotation instanceof HTTP) {
        HTTP http = (HTTP) annotation;
            //调用parseHttpMethodAndPath()
        parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
         //如果是 注解Headers 则代表请求头
      } else if (annotation instanceof retrofit2.http.Headers) {
        //获取对应的String 数组
        String[] headersToParse = ((retrofit2.http.Headers) annotation).value(); 
         //判断数组长度
        if (headersToParse.length == 0) {
          //这里可见如果一定使用@Headers 注解,则一定要有内容,否则会报错。
          throw methodError("@Headers annotation is empty.");
        }
         //调用parseHeaders()方法来解析headersToParse
        headers = parseHeaders(headersToParse);
         //如果 是Multipart注解,则代表用文件提交
      } else if (annotation instanceof Multipart) {
         //如果是文件提交,则不能使用表单提交,这是互斥的
        if (isFormEncoded) {
          throw methodError("Only one encoding annotation is allowed.");
        }
         //给isMultipart赋值为true
        isMultipart = true;
         //如果 是 FormUrlEncoded注解,则代表表单提交
      } else if (annotation instanceof FormUrlEncoded) {
         由于和文件提交互斥,要判断
        if (isMultipart) {
          throw methodError("Only one encoding annotation is allowed.");
        }
        //给isFormEncoded赋值
        isFormEncoded = true;
      }
    }

这个没什么流程,就是不断if else的过程,其中先是判断注解的类型,根据不同的类型来调用parseHttpMethodAndPath方法,这里主要指的是DELETE、GET、HEAD、PATCH、POST、PUT、OPTIONS请求,当然也包括自定义的HTTP请求。然后判断如果Headers,则说明要向请求头里面添加数据。最后做了表单提交和二进制流提交的互斥。那我们接来下就来看下对应的parseHttpMethodAndPath()方法。

3.2.6、 Builder的方法parseHttpMethodAndPath解析

通过方法名,我们理解这个方法主要是"解析HTTP的请求方法和路径",我们一起来看下源码

 private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
      //因为Http请求只能设置一种请求方式,所以先做判断是否已经设置过请求方式,如果设置过则不能重复设置
      if (this.httpMethod != null) {
        throw methodError("Only one HTTP method is allowed. Found: %s and %s.",
            this.httpMethod, httpMethod);
      }
      //设置请求方式
      this.httpMethod = httpMethod;
      //根据不同的请求方式来设置是否需要请求体
      this.hasBody = hasBody;
       //如果注解中没有内容,则返回,因为不需要处理
      if (value.isEmpty()) {
        return;
      }
      //如果在注解的值中存在查询字段,则
      // Get the relative URL path and existing query string, if present.
       //获取注解的值中存在'?'字符的位置
      int question = value.indexOf('?');
         //如果存在,且不是在最后面
      if (question != -1 && question < value.length() - 1) {
        // Ensure the query string does not have any named parameters.
        //确保这个查询字符没有对应的参数
        //获取'?'字符后面的字符串
        String queryParams = value.substring(question + 1);
         //根据正则表达来匹配
        Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams);
        if (queryParamMatcher.find()) {
          throw methodError("URL query string \"%s\" must not have replace block. "
              + "For dynamic query parameters use @Query.", queryParams);
        }
      }
      //把value设置为相对路径的值
      this.relativeUrl = value;
       //最后调用parsePathParameters方法来放置出现重复参数
      this.relativeUrlParamNames = parsePathParameters(value);
    }

大体流程如下:

  • 1、保证请求方式只设置一次
  • 2、设置请求方式和是否需要请求体
  • 3、如果value值为空则return
  • 4、判断value是否有 '?' 查询字段,有的则根据正则表达来判断,如果是符合PARAM_URL_REGEX规则则抛异常。
3.2.7、 Builder的方法parseHeaders解析

这个方法看方法名,可以理解解析请求头

    private Headers parseHeaders(String[] headers) {
      //new 了一个Headers.Builder()对象
      Headers.Builder builder = new Headers.Builder();
       //遍历 字符串数组
      for (String header : headers) {
        获取':'的position下标
        int colon = header.indexOf(':');
        //如果不存在字符':',或者在最前面,或者在最后面 这是不符合header标准,所以抛异常
        if (colon == -1 || colon == 0 || colon == header.length() - 1) {
          throw methodError(
              "@Headers value must be in the form \"Name: Value\". Found: \"%s\"", header);
        }
        //按照':'分类,在':'前面为name,在':'后面为value
        String headerName = header.substring(0, colon);
        String headerValue = header.substring(colon + 1).trim();
         //按照忽略大小写的方法来判断是否是"Content-Type"。
        if ("Content-Type".equalsIgnoreCase(headerName)) {
          如果是"Content-Type",则来获取类型
          MediaType type = MediaType.parse(headerValue);
           //类型不能为null
          if (type == null) {
            throw methodError("Malformed content type: %s", headerValue);
          }
          把类型赋给contentType
          contentType = type;
        } else {
          //如果不是"Content-Type",则添加到 Headers.Builder 里面
          builder.add(headerName, headerValue);
        }
      }
      //调用Headers.Builder的build()方法来返回一个okhttp3.Headers对象
      return builder.build();
    }

  • 1、new 一个Headers.Builder()对象
  • 2、for each遍历headersString数组
  • 3、以':'为分界线前面为key,后面是value
  • 4、如果key是"Content-Type",则获取响应的类型
  • 5、把key和value作为一对,添加到builder中
  • 6、调用builder的build()来获取一个okhttp3.Headers对象,并把它返回。

由于受到简书的篇幅限制,剩下的内容我们将在下一篇文章中解读

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017.06.27 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、ParameterHandler类
    • (一)、ParameterHandler类是什么?
      • (二)、静态内部类RelativeUrl
        • (三)、静态内部类Header
          • (四)、静态内部类Path
            • (五)、静态内部类Query
              • (六)、静态内部类QueryName
                • (七)、静态内部类QueryMap
                  • (八)、静态内部类HeaderMap
                    • (九)、静态内部类Field
                      • (十)、静态内部类FieldMap
                        • (十一)、静态内部类Part
                          • (十二)、静态内部类RawPart
                            • (十三)、静态内部类PartMap
                              • (十四)、静态内部类Body
                                • (十五)、总结
                                • 二、ServiceMethod类
                                  • (一)、ServiceMethod类是什么?
                                    • (二)、ServiceMethod类源码
                                    领券
                                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档