Retrofit 源码深度解析-(2)初始化

正如前一章所说,使用Retrofit的第一步,就是初始化。初始化步骤分为Retrofit实例初始化、Service接口初始化等等,下面的内容将一一阐述。

2.1 初始化Retrofit

2.1.1 初始化时序图

image

2.1.2 new Retrofit.Builder

首先要明确目标:初始化的目的,是为了使用配置信息构建出Retrofit实例

明确这个目标,再看代码就事半功倍。

Retrofit.Builder builder = new Retrofit.Builder();

builder.client(new OkHttpClient());
builder.baseUrl("https://www.baidu.com/");
builder.addCallAdapterFactory(new DefaultCallAdapt.DefaultCallAdaptFactory());
builder.addConverterFactory(new MyConverterFactory());
Retrofit retrofit = builder.build();

第一步,是new一个Retrofit.Builder。因为构建Retrofit的信息比较多,良好的设计风格就是将构建步骤进行收拢,使用Build模式关注构建的步骤。

看一下Builder的定义

image

通过Builder类的定义,大致可以了解到构建Retrofit对象所需的信息,接下来进到方法里面查看详细的构建方式。

2.1.3 platform

Builder的无参构造函数调用了方法Platform.get()。类在第一次使用时会被加载,而加载的时候,进行static变量的初始化,所以static变量PLATFORM 会被Platform.get()时初始化。

Platform对象定义了一些与平台相关的配置信息。

平台指的是JVM的平台,比如Android的Dalvik虚拟机,和服务端常见的HotSpot。

虽然都是JVM,但还是有些细微的差别,比如jdk1.8提供了默认方法的特性,在android低版本上是不存在的。

image

根据Platform的含义以及查看Platform的方法定义,前几个方法就可以知道,定义是为了在不同的虚拟机下,会有一些默认的配置信息。

比如defaultCallAdapterFactories方法内部,就判断了是否是Java8,如果是的话,还提供Java8的CompletableFuture特性:

List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
      @Nullable Executor callbackExecutor) {
    DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
    return hasJava8Types
      	// java 8
        ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
        : singletonList(executorFactory);
}

其他的default开头方法也都差不多

其中重点关注的是invokeDefaultMethodisDefaultMethod

isDefaultMethod方法会根据类属性hasJava8Types来判断,而hasJava8Types的设置,是在Platform初始化时传入,如果是HotSpot则默认是(只有1.8以上才能引入Retrofit包),如果是Android,则会判断SDK版本是否 >= 24

private static Platform findPlatform() {
    return "Dalvik".equals(System.getProperty("java.vm.name"))
        ? new Android() //
        : new Platform(true);
}

Platform(boolean hasJava8Types) {
    this.hasJava8Types = hasJava8Types;
    // 省略一些代码
}

// android 

// 构造函数
Android() {
      super(Build.VERSION.SDK_INT >= 24);
}

invokeDefaultMethod方法有一些特殊的是,使用LockUp实例化Service对象,而这个LockUp对象用了一些不常见的方式得到

lookupConstructor = Lookup.class.getDeclaredConstructor(Class.class, int.class);
lookupConstructor.setAccessible(true);

// 上面的代码在Platform构造函数中

有了特殊的LockUp构造函数对象之后,就可以通过这个这个LockUp构造函数实例化对象,传入-1

Object invokeDefaultMethod(Method method, Class<?> declaringClass, Object object, Object... args)
      throws Throwable {
    Lookup lookup =
        lookupConstructor != null
            ? lookupConstructor.newInstance(declaringClass, -1 /* trusted */)
            : MethodHandles.lookup();
    return lookup.unreflectSpecial(method, declaringClass).bindTo(object).invokeWithArguments(args);
}

关键在于传入了一个-1,而这个-1就是Lookup定义的TRUSTED常量的值

image

image

这一块暂时还不知道为啥,可能就是Default方法在不进行实例化的时候就是不行?我试一下。

如果使用的是默认的MethodHandles.lookup();则会报错

no private access for invokespecial: interface com.gonzo.study.BaiduApi, from retrofit2.Platform

可参考Hotspot MethodHandle详解

有了Platform实例之后,一些平台化的特殊操作,可以交由Platform对象执行 接下来继续回到Builder


2.1.4 callFactory

Retrofit的定义是基于OkHttp3封装的一款轻量级的、让用户可以以定义Service的方式来轻松定义Http请求的框架。

所以框架内部肯定需要一个具体的进行Http请求的实例,也就是OkHttp3定义的okhttp3.Call.Factory。具体可以查看OkHttp相关Demo链接

Retrofit.Builder提供两个方法设置

public Builder client(OkHttpClient client) {
      return callFactory(Objects.requireNonNull(client, "client == null"));
}

public Builder callFactory(okhttp3.Call.Factory factory) {
  this.callFactory = Objects.requireNonNull(factory, "factory == null");
  return this;
}

一般情况下,用Builder client(OkHttpClient client)方法设置OkHttpClient,在设置之前, 也可以用上构建OkHttpClient时可传入的拦截器、代理等等

2.1.5 baseUrl

该属性用作定义baseUrl

Retrofit的使用方式是一个Retrofit实例定义一个全局的baseUrl,然后在Service方法当中定义具体的path。请求是使用baseUrl + path的方式进行拼接请求。

支持多种方式传入,最终会转换成okhttp3.HttpUrl对象

public Builder baseUrl(URL baseUrl) {
  Objects.requireNonNull(baseUrl, "baseUrl == null");
  return baseUrl(HttpUrl.get(baseUrl.toString()));
}

public Builder baseUrl(String baseUrl) {
  Objects.requireNonNull(baseUrl, "baseUrl == null");
  return baseUrl(HttpUrl.get(baseUrl));
}

public Builder baseUrl(HttpUrl baseUrl) {
  Objects.requireNonNull(baseUrl, "baseUrl == null");
  List<String> pathSegments = baseUrl.pathSegments();
  if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
    throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
  }
  this.baseUrl = baseUrl;
  return this;
}

2.1.6 converterFactories

converterFactorie的类型为retrofit2.Converter.Factory,看名字就知道这是一个工厂类,工厂类的作用是用来创建对象,所以这个工厂类就是用来创建Converter对象。

查看retrofit2.Converter.Factory的定义:

image

其中,getParameterUpperBoundgetRawType用来获取参数化类型的工具方法,具体实现也是依赖于Retrofit.Utils工具包。


    /**
     * Extract the upper bound of the generic parameter at {@code index} from {@code type}. For
     * example, index 1 of {@code Map<String, ? extends Runnable>} returns {@code Runnable}.
     */
    protected static Type getParameterUpperBound(int index, ParameterizedType type) {
      return Utils.getParameterUpperBound(index, type);
    }

    /**
     * Extract the raw class type from {@code type}. For example, the type representing {@code
     * List<? extends Runnable>} returns {@code List.class}.
     */
    protected static Class<?> getRawType(Type type) {
      return Utils.getRawType(type);
    }
  }

需要重点关注的,是responseBodyConverter()requestBodyConverter()stringConverter()三个方法,这三个方法定义了三种转换工具类的创建。

2.1.6.1 responseBodyConverter

    /**
     * Returns a {@link Converter} for converting an HTTP response body to {@code type}, or null if
     * {@code type} cannot be handled by this factory. This is used to create converters for
     * response types such as {@code SimpleResponse} from a {@code Call<SimpleResponse>}
     * declaration.
     */
    public @Nullable Converter<ResponseBody, ?> responseBodyConverter(
        Type type, Annotation[] annotations, Retrofit retrofit) {
      return null;
    }

返回用于将 HTTP 响应正文转换为类型的转换器,如果此工厂无法处理类型,则返回 null。

这用于为响应类型创建转换器,例如来自 Call 声明的 SimpleResponse

通过这段描述,可以得知两个关键信息,1、如果当前定义的Converter类无法处理当前type,则返回null类型。2、创建的Converter用于将ResponseBody类型转换为所需要的对象

这个方法会在第一次调用Service 的方法时,解析注解之后被调用,传入当前被调用Service方法的返回值类型(type),遍历所有Factory#responseBodyConverter方法寻找合适的Converter

除了Type,其他两个参数的定义分别为Annotation数组Retrofit实例。Annotation数组是当前被调用方法上的所有注解信息,Retrofit则是当前Retrofit实例

下图是在调用responseBodyConverter()方法时,传入对象的具体信息。

image

至于具体的Converter使用场景,下面在讲到真正调用HttpClientcall方法时会提到。

2.1.6.2 requestBodyConverter

/**
     * Returns a {@link Converter} for converting {@code type} to an HTTP request body, or null if
     * {@code type} cannot be handled by this factory. This is used to create converters for types
     * specified by {@link Body @Body}, {@link Part @Part}, and {@link PartMap @PartMap} values.
*/
public @Nullable Converter<?, RequestBody> requestBodyConverter(
  Type type,
  Annotation[] parameterAnnotations,
  Annotation[] methodAnnotations,
  Retrofit retrofit) {
  return null;
}

responseBodyConverter()方法差不多,也是定义类型转换器,但区别在于requestBodyConverter方法用于定义将请求参数转换成RequestBody

例如,一般使用application/json方式请求,会写成下面这种方式:

@GET("/")
Call<String> get3(@Body Data data);

这种情况下就需要一个转换器将Data类型的数据转换为RequestBody

这个方法同responseBodyConverter一样,在每次第一次运行Service方法,解析方法上的注解构建RequestBuilder时会被调用,传入参数相关信息如下:

image

一般情况下需要关注typeannotations。例如在这个场景里,可以通过判断annotation中是否包含Body注解,来创造一个将对象转换为json之后写入RequestBody的转换器。

至于具体的Converter使用场景,下面在讲到请求参数构建时会提到。

2.1.6.3 stringConverter

 /**
     * Returns a {@link Converter} for converting {@code type} to a {@link String}, or null if
     * {@code type} cannot be handled by this factory. This is used to create converters for types
     * specified by {@link Field @Field}, {@link FieldMap @FieldMap} values, {@link Header @Header},
     * {@link HeaderMap @HeaderMap}, {@link Path @Path}, {@link Query @Query}, and {@link
     * QueryMap @QueryMap} values.
*/
public @Nullable Converter<?, String> stringConverter(
  Type type, Annotation[] annotations, Retrofit retrofit) {
  return null;
}

返回用于将类型转换为字符串的转换器,如果此工厂无法处理类型,则返回 null。这用于为@Field@FieldMap值、@Header@HeaderMap@Path@Query@QueryMap 值指定的类型创建转换器。

通过方法注释可以得知,这个转换器是为了将@Field@FieldMap 值、@Header@HeaderMap@Path@Query@QueryMap注解对应的参数,转换为String类型的转换器。

默认如果没有配置,则会返回一个ToStringConverter,方法内部会简单的调用对象toString()方法。一般情况下在使用上面这些注解时,都只会传入基础类型。

这里有一个疑问,我记得SpringCloudRestTemplate是不支持在get请求中传入一个对象的,这里估计也是不行,可以尝试扩展一下?

至于具体的Converter使用场景,下面在讲到请求参数构建时会提到。

2.1.7 callAdapterFactories

callAdapterFactories是一个retrofit2.CallAdapter.Factory数组,顾名思义,是用来创建CallAdapter的。下面是类定义

image

除去两个工具方法getParameterUpperBoundgetRawType外,get是主要关注的。


/**
     * Returns a call adapter for interface methods that return {@code returnType}, or null if it
     * cannot be handled by this factory.
*/
public abstract @Nullable CallAdapter<?, ?> get(
  Type returnType, Annotation[] annotations, Retrofit retrofit);

通过实现该方法,可以自定义的关心当前类型的CallAdapter

至于CallAdapter是什么,下面的章节会深入讲解,这里只需要知道CallAdapter的定义是通过添加FactoryRetrofit中来的。


2.1.8 callbackExecutor

该属性为执行器。

默认情况下,在调用build方法时,会调用Platform#defaultCallbackExecutor方法,这个方法在Android会被重新实现:

@Override
public Executor defaultCallbackExecutor() {
	return new MainThreadExecutor();
}

同时,在build构建DefaultCallAdapterFactory中会传入这个executor,且DefaultCallAdapterFactory在运行期间,会判断是否存在executor从而创建一个ExecutorCallbackCall

相当于这个字段是提供给android回调用的?


2.1.9 validateEagerly

是否早期校验

该属性用于控制Service方法是在创建Service实例时进行校验和初始化,还是在第一次调用Service方法时进行校验和初始化。

2.1.10 build

在有了初始化Retrofit的所有信息之后,接下来就是进行组装。

public Retrofit build() {
  if (baseUrl == null) {
    throw new IllegalStateException("Base URL required.");
  }

  okhttp3.Call.Factory callFactory = this.callFactory;
  if (callFactory == null) {
    callFactory = new OkHttpClient();
  }

  Executor callbackExecutor = this.callbackExecutor;
  if (callbackExecutor == null) {
    callbackExecutor = platform.defaultCallbackExecutor();
  }

  // Make a defensive copy of the adapters and add the default Call adapter.
  List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
  callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

  // Make a defensive copy of the converters.
  List<Converter.Factory> converterFactories =
    new ArrayList<>(
    1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());

  // Add the built-in converter factory first. This prevents overriding its behavior but also
  // ensures correct behavior when using converters that consume all types.
  converterFactories.add(new BuiltInConverters());
  converterFactories.addAll(this.converterFactories);
  converterFactories.addAll(platform.defaultConverterFactories());

  return new Retrofit(
    callFactory,
    baseUrl,
    unmodifiableList(converterFactories),
    unmodifiableList(callAdapterFactories),
    callbackExecutor,
    validateEagerly);
}

2.1.10.1 设置默认的callAdapterFactory

可以看到,除去最基本的callAdapterFactory,这里还调用Platform添加了基于平台的默认callAdapterFactory。通过查看方法defaultCallAdapterFactories

List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
  @Nullable Executor callbackExecutor) {
  DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
  return hasJava8Types
    ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
    : singletonList(executorFactory);
}

可以得知,如果是java8以上的版本,会添加一个CompletableFutureCallAdapterFactory实例,否则只有一个DefaultCallAdapterFactory

2.1.10.1.1 CompletableFutureCallAdapterFactory

该工厂是为了创建适配CompletableFuture类型的返回值的Convert

查看工厂的get方法:

@Override
public @Nullable CallAdapter<?, ?> get(
  Type returnType, Annotation[] annotations, Retrofit retrofit) {
  // 如果返回类型不是CompletableFuture 则不支持
  if (getRawType(returnType) != CompletableFuture.class) {
    return null;
  }
  
  // 判断返回类型是否是参数化的 不能是CompletableFuture<> 未定义的
  if (!(returnType instanceof ParameterizedType)) {
    throw new IllegalStateException(
      "CompletableFuture return type must be parameterized"
      + " as CompletableFuture<Foo> or CompletableFuture<? extends Foo>");
  }
  // 得到参数化的类型结果 比如 CompletableFuture<Foo> 就是得到 Foo
  Type innerType = getParameterUpperBound(0, (ParameterizedType) returnType);

  // 如果不是Response类型 则返回一个BodyCallAdapter
  if (getRawType(innerType) != Response.class) {
    // Generic type is not Response<T>. Use it for body-only adapter.
    return new BodyCallAdapter<>(innerType);
  }

  // 如果是Response类型 则判断是参数化了 不能是Response<>这种未定义的
  // Generic type is Response<T>. Extract T and create the Response version of the adapter.
  if (!(innerType instanceof ParameterizedType)) {
    throw new IllegalStateException(
      "Response must be parameterized" + " as Response<Foo> or Response<? extends Foo>");
  }
  
  // 得到Response的参数化类型 然后基于这个类型构建一个ResponseCallAdapter
  Type responseType = getParameterUpperBound(0, (ParameterizedType) innerType);
  return new ResponseCallAdapter<>(responseType);
}

可以看到,这个工厂支持构建两种CallAdapterBodyCallAdapterResponseCallAdapter。至于他们的详细区别,在讲到CallAdapter时,会列举所有典型的CallAdapter进行一一解析。

2.1.10.1.2 DefaultCallAdapterFactory

在未进行任何特殊配置的情况下,Retrofit的默认adapter。

居然是默认,那么就会适配平台,所以这里面也会有一些平台相关的信息

通过上面的build调用Platform的代码,可以看到在new DefaultCallAdapterFactory时,传入了一个executor

 DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);

再查看DefaultCallAdapterFactory#get方法:


  @Override
  public @Nullable CallAdapter<?, ?> get(
      Type returnType, Annotation[] annotations, Retrofit retrofit) {
    // 默认只支持Call类型的返回 也就是在Service那边定义返回类型为Call<>
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    // 校验是否参数化
    if (!(returnType instanceof ParameterizedType)) {
      throw new IllegalArgumentException(
          "Call return type must be parameterized as Call<Foo> or Call<? extends Foo>");
    }
    // 获取Call<Foo> 的Foo
    final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);

    // 这是重点,判断Service上是否存在SkipCallbackExecutor注解
    // 不存在的话 返回创建DefaultCallAdapterFactory构造函数传入的executor
    final Executor executor =
        Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
            ? null
            : callbackExecutor;

    // 随后构建一个CallAdapter
    return new CallAdapter<Object, Call<?>>() {
      @Override
      public Type responseType() {
        return responseType;
      }

      @Override
      public Call<Object> adapt(Call<Object> call) {
        // 这里是重点 在存在executor的情况下,会构建一个ExecutorCallbackCall返回 为了适配Android的回调
        return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
      }
    };
  }

方法中除了最基本的校验之外,最需要关注的就是创建CallAdapter时传入的executor。在CallAdapter被调用时,会基于是否存在executor,来断定是否构建ExecutorCallbackCall。这一块关于CallAdapter的在下面讲CallAdapter时,会列举所有典型CallAdapter一一解析。


随后回到build流程当中,在准备好所有的配置信息之后,就可以构建Retrofit

return new Retrofit(
      callFactory,
      baseUrl,
      unmodifiableList(converterFactories),
      unmodifiableList(callAdapterFactories),
      callbackExecutor,
      validateEagerly);

至此,Retrofit构建完成。


2.2 创建Service对象

Retrofit构建完成之后,就是使用Retrofit对象构建我们的Service实例。回顾一下代码:

BaiduApi api = retrofit.create(BaiduApi.class)

BaiduApi定义:

public interface BaiduApi {

    @GET("/")
    Call<String> get1(@Query("aaa") String args);

    @GET("/")
    Response<String> get2(@Query("aaa") String args);

    @GET("/")
    Call<String> get3(@Body Data data);

    @GET("/")
    Call<String> get4(@Header("d") Data d2);

}

2.2.1 创建Service对象时序图

image

2.2.2 Retrofit#create

public <T> T create(final Class<T> service) {
  // 校验
  validateServiceInterface(service);
  
  // 创建动态代理
  return (T)
    Proxy.newProxyInstance(
    service.getClassLoader(),
    new Class<?>[] {service},
    new InvocationHandler() {
      // 平台信息
      private final Platform platform = Platform.get();
      private final Object[] emptyArgs = new Object[0];

      @Override
      public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
        throws Throwable {
        // 如果是Object的方法 则正常调用
        // If the method is a method from Object then defer to normal invocation.
        if (method.getDeclaringClass() == Object.class) {
          return method.invoke(this, args);
        }
        args = args != null ? args : emptyArgs;
        
        // 判断是否是java8的default 方法
        return platform.isDefaultMethod(method) 
          // 使用基于平台特有的执行默认方法的方式
          ? platform.invokeDefaultMethod(method, service, proxy, args) 
          // 先加载方法缓存,再执行
          : loadServiceMethod(method).invoke(args); 
      }
    });
}

create方法分为两部分,先校验,如果通过的话,会基于传入的ServiceClass生成一个动态代理对象返回。

2.2.3 Retrofit#validateServiceInterface

通过查看校验的相关代码,其实可以侧面了解到当前框架支持什么场景,不支持什么场景。

private void validateServiceInterface(Class<?> service) {
  // 先校验是否是一个接口
  if (!service.isInterface()) {
    // 不是接口那肯定没得玩
    throw new IllegalArgumentException("API declarations must be interfaces.");
  }
	
  // 构建一个queue
  Deque<Class<?>> check = new ArrayDeque<>(1);
  // 将当前校验的service添加到第一个
  check.add(service);
  while (!check.isEmpty()) {
    // 获取第一个service class
    Class<?> candidate = check.removeFirst();
    // 校验接口是否定义了泛型 类型形参
    if (candidate.getTypeParameters().length != 0) {
      StringBuilder message =
        new StringBuilder("Type parameters are unsupported on ").append(candidate.getName());
      if (candidate != service) {
        message.append(" which is an interface of ").append(service.getName());
      }
      throw new IllegalArgumentException(message.toString());
    }
    // 将当前接口继承的接口添加到queue中,下一次继续校验
    Collections.addAll(check, candidate.getInterfaces());
  }

  // 是否提前校验、初始化 
  if (validateEagerly) { // 默认false
    Platform platform = Platform.get();
    // 迭代当前类的所有方法
    for (Method method : service.getDeclaredMethods()) {
      // 过滤掉默认方法和static方法
      if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
        // 校验、初始化方法并添加到缓存
        loadServiceMethod(method);
      }
    }
  }
}

通过上面的校验相关代码,可以得知Retrofit是不支持定义了类型形参的接口。例如下面的接口定义:

public interface TypeParametersTestService<A, B, C> {
    A test(B b, C c);
}

在使用Retrofit#create方法构建时,会抛出异常

java.lang.IllegalArgumentException: Type parameters are unsupported on com.gonzo.retrofit.extend.test.service.TypeParametersTestService

为什么不支持?这个可以思考一下。

如果要支持的话,缺少什么?

我觉得关键点在于,如果接口定义了类型形参,那么在创建接口的实例的过程中当中,基于接口方法的返回类型、参数类型选用对应的Convert将会是一件不确定的事情。所以接口必须定义明确。

校验通过之后,会判断是否需要提前校验、初始化。最终会调用Retrofit#loadServiceMethod方法,这个在下面会展开详细描述。

2.3 Proxy#invoke

创建完Service实例之后,接下来就是调用Service的方法:

BaiduApi api = retrofit.create(BaiduApi.class)
Call<String> call = api.get1("test");

继续回顾一下BaiduApi的定义

public interface BaiduApi {

    @GET("/")
    Call<String> get1(@Query("aaa") String args);

    @GET("/")
    Response<String> get2(@Query("aaa") String args);

    @GET("/")
    Call<String> get3(@Body Data data);

    @GET("/")
    Call<String> get4(@Header("d") Data d2);

}

上面的create章节讲到,返回的service对象是一个动态代理对象。熟悉动态代理的同学都知道,这个调用执行到被代理对象的invoke方法,也就是:

public <T> T create(final Class<T> service) {
  // 校验
  validateServiceInterface(service);
  
  // 创建动态代理
  return (T)
    Proxy.newProxyInstance(
    service.getClassLoader(),
    new Class<?>[] {service},
    new InvocationHandler() {
      // 平台信息
      private final Platform platform = Platform.get();
      private final Object[] emptyArgs = new Object[0];

      @Override
      public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
        throws Throwable {
        // 如果是Object的方法 则正常调用
        // If the method is a method from Object then defer to normal invocation.
        if (method.getDeclaringClass() == Object.class) {
          return method.invoke(this, args);
        }
        args = args != null ? args : emptyArgs;
        
        // 判断是否是java8的default 方法
        return platform.isDefaultMethod(method) 
          // 使用基于平台特有的执行默认方法的方式
          ? platform.invokeDefaultMethod(method, service, proxy, args) 
          // 先加载方法缓存,再执行
          : loadServiceMethod(method).invoke(args); 
      }
    });
}

可以看到invoke方法最核心的是最后三句代码。

首先调用platform对象,判断当前方法是否是一个默认方法。这个判断在最开始初始化讲解platform时提到过,内部会根据平台信息判断是否支持默认方法的调用(android平台下是判断sdk api版本)

如果是default方法,再使用Lockup进行调用。这一步涉及到java8的默认方法的一些细节,具体可以查看2.1.3相关信息了解。

如果是非default方法,则会调用Retrofit#loadServiceMethod获取ServiceMethod实例,并执行invoke


2.3.1 Retrofit#loadServiceMethod

Retrofit的对象当中,有一个serviceMethodCache属性,该属性是一个ConcurrentHashMap类型的集合,用作缓存那些已经被加载的ServiceMethod实例。

ServiceMethod<?> loadServiceMethod(Method method) {
  // 缓存获取 存在则直接返回
  ServiceMethod<?> result = serviceMethodCache.get(method);
  if (result != null) return result;

  // 不存在则先加锁
  synchronized (serviceMethodCache) {
    result = serviceMethodCache.get(method);
    if (result == null) {
      // 开始解析
      result = ServiceMethod.parseAnnotations(this, method);
      serviceMethodCache.put(method, result);
    }
  }
  return result;
}

如果缓存不存在,则调用ServiceMethod#parseAnnotations方法进行解析,缓存之后再返回。


2.3.2 ServiceMethod

Retrofit#loadServiceMethod方法的返回类型为ServiceMethod,该对象定义从名字可以看出来,是对Service的方法的抽象。

查看ServiceMethod的定义:

image

可以看到有两个关键的方法invokeparseAnnotations。其中parseAnnotations是一个static方法,通过方法签名可以大概揣测到这是一个提供创建ServiceMethod实例的工厂方法

事实也是如此,Retrofit#loadServiceMethod就是通过调用ServiceMethod#parseAnnotations来获取ServiceMethod实例。

同时ServiceMethod有几个实现类

image

其中HttpServiceMethod继承自ServiceMethod,而CallAdaptedSuspendForResponseSuspendForBody继承自HttpServiceMethod

具体UML图如下:

image

其中HttpServiceMethod实现了ServiceMethodinvoke方法

@Override
final @Nullable ReturnT invoke(Object[] args) {
  // 创建一个OkHttpCall对象
  Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
  // 转到adapt方法执行
  return adapt(call, args);
}

HttpServiceMethod自己定义了adapt方法供子类实现

protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);

CallAdaptedSuspendForResponseSuspendForBody都实现了HttpServiceMethodadapt方法。

2.3.2.1 SuspendForResponse和SuspendForBody

这两个其实是Kotlin相关支持的ServiceMethod,具体特性由于对kotlin不是很熟悉,所以就不多说了。

2.3.2.2 CallAdapted

在默认的服务端开发情况下,返回的ServiceMethod实例都是这个类型。这个类的定义也很简单,起到一个适配的作用:

static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
  private final CallAdapter<ResponseT, ReturnT> callAdapter;

  CallAdapted(
    RequestFactory requestFactory,
    okhttp3.Call.Factory callFactory,
    Converter<ResponseBody, ResponseT> responseConverter,
    CallAdapter<ResponseT, ReturnT> callAdapter) {
    super(requestFactory, callFactory, responseConverter);
    this.callAdapter = callAdapter;
  }

  @Override
  protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
    // 转到CallAdapter执行
    return callAdapter.adapt(call);
  }
}

知道类的大概结构和关系图之后,接下来开始深入到parseAnnotations方法,来详细捋一捋是如何创建ServiceMethod对象的。

2.3.2.3 parseAnnotations

先看一下这个静态方法的代码

static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
  // 解析方法注解 构建出一个RequestFactory
  RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
  
  // 获取方法的正式返回值类型 例如List<String> 返回的就是 List<String> 而不是List
  Type returnType = method.getGenericReturnType();
  // 判断是否还存在未明确的类型 例如List<?>、T、List<? extend Object> 等等
  if (Utils.hasUnresolvableType(returnType)) {
    throw methodError(
      method,
      "Method return type must not include a type variable or wildcard: %s",
      returnType);
  }
  // void返回值也是不支持的
  if (returnType == void.class) {
    throw methodError(method, "Service methods cannot return void.");
  }
  // 转到 HttpServiceMethod#parseAnnotations
  return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
  1. 先调用RequestFactory#parseAnnotations得到RequestFactory对象,该对象就是作在service方法调用时,根据参数进行构建出Request的对象。具体的内部详细实现逻辑,下面会进行讲解。
  2. 进行校验,判断方法的返回类型是否是明确的,比如不能是List<?>TList<? extend Object> 等等。这些对应的类型在Java当中都有对应的类表示(GenericArrayType、TypeVariable、WildcardType可以看我的另外一篇博客)。同时返回类型也不能是void。
  3. 校验通过之后,跳到HttpServiceMethod#parseAnnotations
 static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    // 判断是否是kotlin
    boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
    boolean continuationWantsResponse = false;
    boolean continuationBodyNullable = false;

    Annotation[] annotations = method.getAnnotations();
    // 定义adapter的类型
    Type adapterType;
    if (isKotlinSuspendFunction) {
       // kotlin 相关处理 略过
    } else {
      // Java 处理 直接获取方法的正式返回类型 List<String> 
      adapterType = method.getGenericReturnType();
    }

    // 获取CallAdapter
    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
    // CallAdapter的responseType
    Type responseType = callAdapter.responseType();

    // CallAdapter不支持直接返回okhttp3.Response类型 算是一个限制
    if (responseType == okhttp3.Response.class) {
      throw methodError(
          method,
          "'"
              + getRawType(responseType).getName()
              + "' is not a valid response body type. Did you mean ResponseBody?");
    }

    // Response的class定义为Response<T>,所以不能直接返回 Response 而是需要指定Response的类型形参
    if (responseType == Response.class) {
      throw methodError(method, "Response must include generic type (e.g., Response<String>)");
    }

    // HEAD类型的请求 CallAdapter的responseType必须是Void类型 这是为啥? 可是前面不是判断方法的返回值不能为Void吗
    // 噢,是不能为void 但是可以为Void....
    // TODO support Unit for Kotlin?
    if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
      throw methodError(method, "HEAD method must use Void as response type.");
    }

    // 获取responseConverter
    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);

    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    if (!isKotlinSuspendFunction) {
      // 非kotlin 返回一个CallAdapted实例
      return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
    } else if (continuationWantsResponse) {
      // kotlin 相关处理 ...
  }

忽略kotlin的相关处理,核心流程有如下几个

  1. 获取方法的返回类型,用作查询CallAdapter所支持的type类型传入。
  2. 校验CallAdapter的返回类型,不能是okhttp3.Response,也不能是未定义详细类型的Response
  3. 根据CallAdapter所定义的responseType,获取ResponseConvert
  4. 使用requestFactorycallFactoryresponseConvertercallAdapter new一个CallAdapted实例返回。

通过以上的流程,可以了解到,方法的返回类型决定了CallAdapter的类型(所以CallAdapter会有很多实现类,用来支持Java8、RxJava等等),而CallAdapterresponseType决定了responseConverter的类型。

接下来针对每一个流程进行深入

2.3.3 RequestFactory

调用ServiceMethod#parseAnnotations方法的第一步,就调用了RequestFactory#parseAnnotations方法,接下来针对这个方法进行解析,看看这个方法内部到底做了什么。

在去分析RequestFactory时,换个角度思考,当我们要自己去实现一个类似的Http请求的框架时,肯定是会将构造okhttp3.Request的代码进行抽取,在每次调用Service方法发起Http请求时,使用方法上的注解信息、参数信息构建出一个okhttp3.Request。当然,实际情况下会考虑很多特殊情况,但大体思路是对的。

先看看RequestFactory的定义

image

可以看到RequestFactory类定义了创建Request需要的信息(方法、url、param、header等等)。同时由于这些信息都是通过Service方法上的注解上解析得到了,所以针对解析、创建RequestFactory这个步骤,交由RequestFactory内部的Builder处理

进入RequestFactory.parseAnnotations方法后,熟悉的套路

static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
  return new Builder(retrofit, method).build();
}

创建了一个Builder,将RequestFactory的构建步骤给流程化了了。

2.3.3.1 RequestFactory.Builder

通过上面的Builder 的UML图可以看到,Builder类当中包含大量的配置字段,这些字段看名字大概都能猜到什么意思。而Builder的处理流程,就是将方法上的信息转换成Builder的配置字段,最终根据配置字段构建出RequestFactory实例返回。

一部分字段的值通过构造函数确定:

Builder(Retrofit retrofit, Method method) {
  this.retrofit = retrofit;
  this.method = method;
  this.methodAnnotations = method.getAnnotations();
  this.parameterTypes = method.getGenericParameterTypes();
  this.parameterAnnotationsArray = method.getParameterAnnotations();
}

现在开始进入Builder#build方法:

RequestFactory build() {
  // 解析方法的注解 GET POST HEAD 等等注解
  for (Annotation annotation : methodAnnotations) {
    parseMethodAnnotation(annotation);
  }
  
  if (httpMethod == null) {
    throw methodError(method, "HTTP method annotation is required (e.g., @GET, @POST, etc.).");
  }
  
  // 解析完之后进行校验
  if (!hasBody) {
    if (isMultipart) {
      throw methodError(
        method,
        "Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
    }
    if (isFormEncoded) {
      throw methodError(
        method,
        "FormUrlEncoded can only be specified on HTTP methods with "
        + "request body (e.g., @POST).");
    }
  }
  
  // 参数数量
  int parameterCount = parameterAnnotationsArray.length;
  parameterHandlers = new ParameterHandler<?>[parameterCount];
  // 解析参数信息,转换成ParameterHandler类型
  for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
    parameterHandlers[p] =
      parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
  }
	
  // 继续校验
  if (relativeUrl == null && !gotUrl) {
    throw methodError(method, "Missing either @%s URL or @Url parameter.", httpMethod);
  }
  if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
    throw methodError(method, "Non-body HTTP method cannot contain @Body.");
  }
  if (isFormEncoded && !gotField) {
    throw methodError(method, "Form-encoded method must contain at least one @Field.");
  }
  if (isMultipart && !gotPart) {
    throw methodError(method, "Multipart method must contain at least one @Part.");
  }
  
  // 构建
  return new RequestFactory(this);
}
2.3.3.1.1 解析注解信息

先回顾一下之前定义的BaiduApi

public interface BaiduApi {
    @GET("/")
    Call<String> get1(@Query("aaa") String args);
}

可以看到,我们需要构建的Request信息,是通过方法的注解、方法返回值、参数的注解和参数信息得到的。

所以先从解析方法注解开始

private void parseMethodAnnotation(Annotation annotation) {
  if (annotation instanceof DELETE) {
    parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
  } else if (annotation instanceof GET) {
    parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
  } else if (annotation instanceof HEAD) {
    parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
  } else if (annotation instanceof PATCH) {
    parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
  } else if (annotation instanceof POST) {
    parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
  } else if (annotation instanceof PUT) {
    parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
  } else if (annotation instanceof OPTIONS) {
    parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
  } else if (annotation instanceof HTTP) {
    HTTP http = (HTTP) annotation;
    parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
  } else if (annotation instanceof retrofit2.http.Headers) {
    String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
    if (headersToParse.length == 0) {
      throw methodError(method, "@Headers annotation is empty.");
    }
    // 解析头
    headers = parseHeaders(headersToParse);
  } else if (annotation instanceof Multipart) {
    if (isFormEncoded) {
      throw methodError(method, "Only one encoding annotation is allowed.");
    }
    // 是一个Multipart请求
    isMultipart = true;
  } else if (annotation instanceof FormUrlEncoded) {
    if (isMultipart) {
      throw methodError(method, "Only one encoding annotation is allowed.");
    }
    // 是一个Form请求
    isFormEncoded = true;
  }
}

注解信息分为两部分:请求方式如GET、POST等等,配置信息如Headers、Multipart和FormUrlEncoded。

请求方式的相关注解都会被转到parseHttpMethodAndPath方法执行

Headers相关解析会转到parseHeaders方法执行

而Multipart和FormUrlEncoded则会影响isMultipart和isFormEncoded的值

2.3.3.1.2 parseHttpMethodAndPath
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
  // 避免重复设置
  if (this.httpMethod != null) {
    throw methodError(
      method,
      "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.
    // 避免出现 ?aaa={aaa}的用法
    String queryParams = value.substring(question + 1);
    Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams);
    if (queryParamMatcher.find()) {
      throw methodError(
        method,
        "URL query string \"%s\" must not have replace block. "
        + "For dynamic query parameters use @Query.",
        queryParams);
    }
  }

  this.relativeUrl = value;
  // 解析path上的请求 如: /aaa/bbb/{id}/ccc 中的id
  this.relativeUrlParamNames = parsePathParameters(value);
}

通过这一步,确定httpMethod、hasBody、relativeUrl和relativeUrlParamNames。

2.3.3.1.3 parseHeaders

@Headers注解也是方法注解,其用法为

public interface BaiduApi {
    @GET("/")
    @Headers({"contentType:applicationJson"})
    Call<String> get1(@Query("aaa") String args);
}

对应的解析代码:

private Headers parseHeaders(String[] headers) {
  Headers.Builder builder = new Headers.Builder();
  for (String header : headers) {
    int colon = header.indexOf(':');
    // 校验是否是 : 分割的
    if (colon == -1 || colon == 0 || colon == header.length() - 1) {
      throw methodError(
        method, "@Headers value must be in the form \"Name: Value\". Found: \"%s\"", header);
    }
    // key
    String headerName = header.substring(0, colon);
    // value
    String headerValue = header.substring(colon + 1).trim();
    // 针对Content-Type的特殊处理 这个关系到当前请求的请求类型
    if ("Content-Type".equalsIgnoreCase(headerName)) {
      try {
        contentType = MediaType.get(headerValue);
      } catch (IllegalArgumentException e) {
        throw methodError(method, e, "Malformed content type: %s", headerValue);
      }
    } else {
      // 否则添加到builder当中
      builder.add(headerName, headerValue);
    }
  }
  // build
  return builder.build();
}

解析代码也很平常,就是针对Content-Type类型做了特殊处理,其他情况下使用OkHttp3Headers.builder进行Headers的构建。

经过以上几个步骤,方法上的相关注解都解析完成了,现在开始参数注解解析,这也是最复杂的部分。

2.3.3.1.4 解析参数注解信息

回顾上面的build方法的代码片段:

// parameterAnnotationsArray 是在构建Builder时,通过method.getParameterAnnotations();得到的
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
  parameterHandlers[p] =
    parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
}

可以看到,每一个参数以及参数对应的位置信息、注解信息被包装成了一个ParameterHandler对象

abstract class ParameterHandler<T> {
  abstract void apply(RequestBuilder builder, @Nullable T value) throws IOException;
}

ParameterHandler

ParameterHandler的定义,就是将对应的param基于规则进行转换。可能说起来有点模糊,下面会详细说明。

回到build#parseParameter方法,解析得到ParameterHandler对象:

 private @Nullable ParameterHandler<?> parseParameter(
   int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
   ParameterHandler<?> result = null;
   if (annotations != null) {
     // 循环解析annotation
     for (Annotation annotation : annotations) {
       ParameterHandler<?> annotationAction =
         // 解析
         parseParameterAnnotation(p, parameterType, annotations, annotation);

       if (annotationAction == null) {
         continue;
       }
       
       // 避免出现使用多个注解的情况
       if (result != null) {
         throw parameterError(
           method, p, "Multiple Retrofit annotations found, only one allowed.");
       }

       result = annotationAction;
     }
   }
   
   // 避免出现类似于  Call<String> get10(@Path("aaa") String args, String args2, @Path("bbb") String args3);
   // 这种第二个参数没有注解的情况出现
   // 感觉这个应该可以不用管吧?可能是为了避免错误使用?
   if (result == null) {
     if (allowContinuation) {
       try {
         if (Utils.getRawType(parameterType) == Continuation.class) {
           isKotlinSuspendFunction = true;
           return null;
         }
       } catch (NoClassDefFoundError ignored) {
       }
     }
     throw parameterError(method, p, "No Retrofit annotation found.");
   }

   return result;
 }

继续查看parseParameterAnnotation

private ParameterHandler<?> parseParameterAnnotation(
  int p, Type type, Annotation[] annotations, Annotation annotation) {
  // 代码特别长.....
}

由于代码太长,且内部都是if else,所以这里进行截取片段的方式一个个讲解。


2.3.3.1.5 Url

用法:

Call<String> get12(@Url String url);

解析:

if (annotation instanceof Url) {
  // 校验当前参数的类型是否是明确的,不能是List<?> 这种
  validateResolvableType(p, type);
  // 避免重复设置
  if (gotUrl) {
    throw parameterError(method, p, "Multiple @Url method annotations found.");
  }
  // @Path不能和@Url一起用
  if (gotPath) {
    throw parameterError(method, p, "@Path parameters may not be used with @Url.");
  }
  // @Url必须在@Query之前
  if (gotQuery) {
    throw parameterError(method, p, "A @Url parameter must not come after a @Query.");
  }
  // @Url必须在@QueryName之前
  if (gotQueryName) {
    throw parameterError(method, p, "A @Url parameter must not come after a @QueryName.");
  }
  //  @Url必须在@QueryMap之前
  if (gotQueryMap) {
    throw parameterError(method, p, "A @Url parameter must not come after a @QueryMap.");
  }
  // 不能跟GET POST等方法注解冲突
  if (relativeUrl != null) {
    throw parameterError(method, p, "@Url cannot be used with @%s URL", httpMethod);
  }

  gotUrl = true;

  if (type == HttpUrl.class
      || type == String.class
      || type == URI.class
      || (type instanceof Class && "android.net.Uri".equals(((Class<?>) type).getName()))) {
    return new ParameterHandler.RelativeUrl(method, p);
  } else {
    throw parameterError(
      method,
      p,
      "@Url must be okhttp3.HttpUrl, String, java.net.URI, or android.net.Uri type.");
  }
}

可以看到,在做了一些规则校验之后,生成了一个RelativeUrl实例

static final class RelativeUrl extends ParameterHandler<Object> {
  private final Method method;
  private final int p;

  RelativeUrl(Method method, int p) {
    this.method = method;
    this.p = p;
  }

  @Override
  void apply(RequestBuilder builder, @Nullable Object value) {
    if (value == null) {
      throw Utils.parameterError(method, p, "@Url parameter is null.");
    }
    builder.setRelativeUrl(value);
  }
}

通过RelativeUrlapply方法的实现,大概就能明白ParameterHandler的定义:将Request的构建中,方法上的参数的转换交由一个个对应的ParameterHandler实现。

就像是上面的RelativeUrl,基于@Url注解得到,通过调用apply方法,将@Url注解对应的参数的值设置为relativeUrl

继续回到参数解析

2.3.3.1.6 Path

用法:

@GET("/{aaa}/?aaa=c")
Call<String> get10(@Path("aaa") String args, String args2, @Path("bbb") String args3);

解析代码:

else if (annotation instanceof Path) {
  validateResolvableType(p, type);
  // 不能在@Query之后
  if (gotQuery) {
    throw parameterError(method, p, "A @Path parameter must not come after a @Query.");
  }
  // 不能在@QueryName之后
  if (gotQueryName) {
    throw parameterError(method, p, "A @Path parameter must not come after a @QueryName.");
  }
  // 不能在@QueryMap之后
  if (gotQueryMap) {
    throw parameterError(method, p, "A @Path parameter must not come after a @QueryMap.");
  }
  // 不能和@Url一起食用
  if (gotUrl) {
    throw parameterError(method, p, "@Path parameters may not be used with @Url.");
  }
  // 必须和relativeUrl一起食用
  if (relativeUrl == null) {
    throw parameterError(
      method, p, "@Path can only be used with relative url on @%s", httpMethod);
  }
  gotPath = true;

  Path path = (Path) annotation;
  String name = path.value();
  validatePathName(p, name);
  
  // 获取一个StringConverter 默认是BuiltInConverters.ToStringConverter类型
  Converter<?, String> converter = retrofit.stringConverter(type, annotations);
  // 构建一个ParameterHandler.Path实例
  return new ParameterHandler.Path<>(method, p, name, converter, path.encoded());
} 

在进行@Path注解使用的一些限制校验之后,从Retrofit实例中获取到StringConverter,构建出一个ParameterHandler.Path实例:

static final class Path<T> extends ParameterHandler<T> {
  private final Method method;
  private final int p;
  private final String name;
  private final Converter<T, String> valueConverter;
  private final boolean encoded;

  Path(Method method, int p, String name, Converter<T, String> valueConverter, boolean encoded) {
    this.method = method;
    this.p = p;
    this.name = Objects.requireNonNull(name, "name == null");
    this.valueConverter = valueConverter;
    this.encoded = encoded;
  }

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

Path#apply方法内部通过调用RequestBuilder#addPathParam来达到替换path当中的占位符的效果

void addPathParam(String name, String value, boolean encoded) {
  if (relativeUrl == null) {
    // The relative URL is cleared when the first query parameter is set.
    throw new AssertionError();
  }
  String replacement = canonicalizeForPath(value, encoded);
  // replace方法替换
  String newRelativeUrl = relativeUrl.replace("{" + name + "}", replacement);
  if (PATH_TRAVERSAL.matcher(newRelativeUrl).matches()) {
    throw new IllegalArgumentException(
      "@Path parameters shouldn't perform path traversal ('.' or '..'): " + value);
  }
  // 然后设置为新的
  relativeUrl = newRelativeUrl;
}
2.3.3.1.7 Query

使用方式:

@GET("/")
Call<String> get1(@Query("aaa") String args);

@GET("/")
Call<String> get13(@Query("aaa") List<String> args);

@GET("/")
Call<String> get14(@Query("aaa") List<?> args); // 错误用法

@GET("/")
Call<String> get15(@Query("aaa") String[] args);

解析:

else if (annotation instanceof Query) {
  // 避免未确定的参数类型
  validateResolvableType(p, type);
  Query query = (Query) annotation;
  String name = query.value();
  boolean encoded = query.encoded();
  // rowType是外层的类型,例如List<String> 的rowType就是List
  Class<?> rawParameterType = Utils.getRawType(type);
  gotQuery = true;
  if (Iterable.class.isAssignableFrom(rawParameterType)) {
    // ParameterizedType的类型代表的是 例如 List<String> 这种整个类型
    if (!(type instanceof ParameterizedType)) { 
      // 不能是 List 这种未指定具体类型的
      throw parameterError(
        method,
        p,
        rawParameterType.getSimpleName()
        + " must include generic type (e.g., "
        + rawParameterType.getSimpleName()
        + "<String>)");
    }
    ParameterizedType parameterizedType = (ParameterizedType) type;
    // 获取到List<String> 当中的String类型
    Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
    Converter<?, String> converter = retrofit.stringConverter(iterableType, annotations);
    // 构建一个ParameterHandler.Query对象
    return new ParameterHandler.Query<>(name, converter, encoded)
      // 转换成适配iterable的ParameterHandler
      .iterable();
  } else if (rawParameterType.isArray()) {
    // 数组类型
    // 装箱
    Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
    Converter<?, String> converter =
      retrofit.stringConverter(arrayComponentType, annotations);
    // 构建一个ParameterHandler.Query对象
    return new ParameterHandler.Query<>(name, converter, encoded)
       // 转换成适配array的ParameterHandler
      .array();
  } else {
    // 最简单的toString
    Converter<?, String> converter = retrofit.stringConverter(type, annotations);
    // 构建一个ParameterHandler.Query对象
    return new ParameterHandler.Query<>(name, converter, encoded);
  }
}

解析Query的步骤有三个分支,Iterable参数、Array参数和普通参数。

其中Iterable参数和Array有一个特殊的调用为

return new ParameterHandler.Query<>(name, converter, encoded).iterable();` 和`return new ParameterHandler.Query<>(name, converter, encoded).array();

通过查看ParameterHandler对应方法的定义:

final ParameterHandler<Iterable<T>> iterable() {
  return new ParameterHandler<Iterable<T>>() {
    @Override
    void apply(RequestBuilder builder, @Nullable 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));
      }
    }
  };
}

这两个方法相当于创建一个适配器,以一种优雅的方式解决了ArrayIterable类型的兼容。

因为默认情况下ParameterHandlerl理解为处理一个单一的对象,但确实有集合类型的对象需要处理,如果为了兼容集合类型要么就是在每一个ParameterHandler实现类当中针对类型做判断,然后走集合的处理或者单一对象的处理,要么就是用现在这个吊炸天的方式,写一个基于单一ParameterHandler的集合适配。

这个代码还是很吊的,我就写不出来,一开始看了半天,没太明白这个是解决什么的。这个思路可以好好学习下。

可以参考一下写个Demo

public abstract class Join<T> {

    abstract void join(T t);

    Join<Iterable<T>> iterable() {
        return new Join<Iterable<T>>() {
            @Override
            void join(Iterable<T> tIterable) {
                for (T t : tIterable) {
                    Join.this.join(t);
                }
            }
        };
    }

    static class JoinImpl extends Join<String> {

        @Override
        void join(String s) {
            System.out.println(s);
        }
    }


    public static void main(String[] args) {
        Join<Iterable<String>>  join = new JoinImpl().iterable();
        join.join(Arrays.asList("1", "2", "3", "4", "5"));
				/**
					1
          2
          3
          4
          5
				*/
    }
}

很牛批


2.3.3.1.8 QueryName

用法:

@GET("/test")
Call<String> get16(@QueryName String args); // api.get16("get") = /test?get

@GET("/test")
Call<String> get17(@QueryName String[] args);// api.get16("get", "set") = /test?get&set

这个好像用的不多,但是一些特殊的语法查询会用到。

解析代码:

else if (annotation instanceof QueryName) {
  // 校验类型
  validateResolvableType(p, type);
  QueryName query = (QueryName) annotation;
  boolean encoded = query.encoded();
	// 得到List<String> 的List这个类型
  Class<?> rawParameterType = Utils.getRawType(type);
  gotQueryName = true;
  // 如果是集合
  if (Iterable.class.isAssignableFrom(rawParameterType)) {
    // 那么是不是还没确定类型
    if (!(type instanceof ParameterizedType)) {
      throw parameterError(
        method,
        p,
        rawParameterType.getSimpleName()
        + " must include generic type (e.g., "
        + rawParameterType.getSimpleName()
        + "<String>)");
    }
    // 得到参数化的类型 List<String> 的List<String>这个类型
    ParameterizedType parameterizedType = (ParameterizedType) type;
    // 获取List<String> 的String这个类型
    Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
    Converter<?, String> converter = retrofit.stringConverter(iterableType, annotations);
    // 老套路 new 一个ParameterHandler.QueryName 然后调用iterable的优雅处理
    return new ParameterHandler.QueryName<>(converter, encoded).iterable();
  } else if (rawParameterType.isArray()) {
    // 集合
    Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
    Converter<?, String> converter =
      retrofit.stringConverter(arrayComponentType, annotations);
    return new ParameterHandler.QueryName<>(converter, encoded).array();
  } else {
    // 普通的String
    Converter<?, String> converter = retrofit.stringConverter(type, annotations);
    return new ParameterHandler.QueryName<>(converter, encoded);
  }

}

看一下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, @Nullable T value) throws IOException {
    if (value == null) return; // Skip null values.
    // 通过转换器转换后调用RequestBuilder#addQueryParam方法 这里重点在于传入的value 是一个null
    builder.addQueryParam(nameConverter.convert(value), null, encoded);
  }
}

查看RequestBuilder#addQueryParam方法

void addQueryParam(String name, @Nullable String value, boolean encoded) {
  // 得到最新的urlBuilder
  if (relativeUrl != null) {
    // Do a one-time combination of the built relative URL and the base URL.
    urlBuilder = baseUrl.newBuilder(relativeUrl);
    if (urlBuilder == null) {
      throw new IllegalArgumentException(
        "Malformed URL. Base: " + baseUrl + ", Relative: " + relativeUrl);
    }
    relativeUrl = null;
  }
  
  // 使用urlBuilder添加 QueryParameter
  if (encoded) {
    //noinspection ConstantConditions Checked to be non-null by above 'if' block.
    urlBuilder.addEncodedQueryParameter(name, value);
  } else {
    //noinspection ConstantConditions Checked to be non-null by above 'if' block.
    urlBuilder.addQueryParameter(name, value);
  }
}

2.3.3.1.9 QueryMap

用法:

@GET("/test")
Call<String> get18(@QueryMap Map<String, String> queryMap);
// 例如 调用api.get18(Maps.asMap("a", "b", "a1", "b1")) 则到结果 /test?a=b&a1=b1

解析代码:

else if (annotation instanceof QueryMap) {
  // 校验类型
  validateResolvableType(p, type);
  Class<?> rawParameterType = Utils.getRawType(type);
  gotQueryMap = true;
  if (!Map.class.isAssignableFrom(rawParameterType)) {
    throw parameterError(method, p, "@QueryMap parameter type must be Map.");
  }
  
  // 获取Map类型
  Type mapType = Utils.getSupertype(type, rawParameterType, Map.class);
  if (!(mapType instanceof ParameterizedType)) {
    throw parameterError(
      method, p, "Map must include generic types (e.g., Map<String, String>)");
  }
  // 校验是否存在未定义的类型
  ParameterizedType parameterizedType = (ParameterizedType) mapType;
  // 得到Map<Object, String>的 Object
  Type keyType = Utils.getParameterUpperBound(0, parameterizedType);
  // key只支持String
  if (String.class != keyType) {
    throw parameterError(method, p, "@QueryMap keys must be of type String: " + keyType);
  }
  // 得到得到Map<Object, String>的 String
  Type valueType = Utils.getParameterUpperBound(1, parameterizedType);
  Converter<?, String> valueConverter = retrofit.stringConverter(valueType, annotations);
	
  // 老套路
  return new ParameterHandler.QueryMap<>(
    method, p, valueConverter, ((QueryMap) annotation).encoded());

}

看一下ParameterHandler.QueryMap的实现:

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

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

  @Override
  void apply(RequestBuilder builder, @Nullable Map<String, T> value) throws IOException {
    if (value == null) {
      throw Utils.parameterError(method, p, "Query map was null");
    }
    
    // 迭代
    for (Map.Entry<String, T> entry : value.entrySet()) {
      String entryKey = entry.getKey();
      // 校验
      if (entryKey == null) {
        throw Utils.parameterError(method, p, "Query map contained null key.");
      }
      T entryValue = entry.getValue();
      if (entryValue == null) {
        throw Utils.parameterError(
          method, p, "Query map contained null value for key '" + entryKey + "'.");
      }
      
      // 调用类型转换器进行转换成String类型的
      String convertedEntryValue = valueConverter.convert(entryValue);
      if (convertedEntryValue == null) {
        throw Utils.parameterError(
          method,
          p,
          "Query map value '"
          + entryValue
          + "' converted to null by "
          + valueConverter.getClass().getName()
          + " for key '"
          + entryKey
          + "'.");
      }
      // 调用 RequestBuilder#addQueryParam方法
      builder.addQueryParam(entryKey, convertedEntryValue, encoded);
    }
  }
}

可以看到,内部最终还是同QueryQueryName一样,调用RequestBuilder#addQueryParam添加query参数。


2.3.3.1.10 Header

使用方式:

@GET("/")
Call<String> get4(@Header("d") Data d2);

解析代码:

else if (annotation instanceof Header) {
  // 剔除掉一些校验代码
  Header header = (Header) annotation;
  String name = header.value();
  Class<?> rawParameterType = Utils.getRawType(type);
  if (Iterable.class.isAssignableFrom(rawParameterType)) {
    ParameterizedType parameterizedType = (ParameterizedType) type;
    Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
    Converter<?, String> converter = retrofit.stringConverter(iterableType, annotations);
    // 实例化ParameterHandler.Header 
    return new ParameterHandler.Header<>(name, converter).iterable();
  } else if (rawParameterType.isArray()) {
    Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
    Converter<?, String> converter =
      retrofit.stringConverter(arrayComponentType, annotations);
    // 实例化ParameterHandler.Header 
    return new ParameterHandler.Header<>(name, converter).array();
  } else {
    Converter<?, String> converter = retrofit.stringConverter(type, annotations);
    // 实例化ParameterHandler.Header 
    return new ParameterHandler.Header<>(name, converter);
  }
}

看看ParameterHandler.Header的定义:

 static final class Header<T> extends ParameterHandler<T> {
   // 剔除构造函数等定义

   @Override
   void apply(RequestBuilder builder, @Nullable T value) throws IOException {
     // 简化校验等代码
     String headerValue = valueConverter.convert(value);
     builder.addHeader(name, headerValue);
   }
 }

最终还是调用的RequestBuilder#addHeader,上面已经介绍过了。


2.3.3.1.11 HeaderMap

使用方式:

@GET("/")
Call<String> get19(@HeaderMap Map<String, String> headerMap);

解析代码:

else if (annotation instanceof HeaderMap) {
	// 简化一下 剔除了校验的代码
  Class<?> rawParameterType = Utils.getRawType(type);
  Type mapType = Utils.getSupertype(type, rawParameterType, Map.class);
  ParameterizedType parameterizedType = (ParameterizedType) mapType;
  // 获取key value的类型
  Type keyType = Utils.getParameterUpperBound(0, parameterizedType);
  Type valueType = Utils.getParameterUpperBound(1, parameterizedType);
  // 得到value转换器
  Converter<?, String> valueConverter = retrofit.stringConverter(valueType, annotations);
	// 构建HeaderMap的ParameterHandler
  return new ParameterHandler.HeaderMap<>(method, p, valueConverter);
}

查看ParameterHandler.HeaderMap的定义:

static final class HeaderMap<T> extends ParameterHandler<Map<String, T>> {
  // 移除构造函数等代码

  @Override
  void apply(RequestBuilder builder, @Nullable Map<String, T> value) throws IOException {
    
    for (Map.Entry<String, T> entry : value.entrySet()) {
      String headerName = entry.getKey();
      
      T headerValue = entry.getValue();
      
      builder.addHeader(headerName, valueConverter.convert(headerValue));
    }
  }
}

可以看到,同Header一样,最终还是调用的RequestBuilder#addHeader


2.3.3.1.12 Field

使用方式:

@POST("/")
Call<String> get20(@Field("name") String field);

这个是配合普通的post application/x-www-form-urlencoded请求,表单提交用的。类似于:

POST http://www.example.com HTTP/1.1
Content-Type: application/x-www-form-urlencoded;charset=utf-8

title=test&sub%5B%5D=1&sub%5B%5D=2&sub%5B%5D=3

解析代码:

else if (annotation instanceof Field) {
  
  // 移除了校验代码
  Field field = (Field) annotation;
  String name = field.value();
  boolean encoded = field.encoded();
  // 设置标志位
  gotField = true;

  Class<?> rawParameterType = Utils.getRawType(type);
  if (Iterable.class.isAssignableFrom(rawParameterType)) {
    // 集合类型
    ParameterizedType parameterizedType = (ParameterizedType) type;
    Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
    Converter<?, String> converter = retrofit.stringConverter(iterableType, annotations);
    // new一个ParameterHandler.Field 并对集合类型适配
    return new ParameterHandler.Field<>(name, converter, encoded).iterable();
  } else if (rawParameterType.isArray()) {
    Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
    Converter<?, String> converter =
      retrofit.stringConverter(arrayComponentType, annotations);
    // new一个ParameterHandler.Field 并对数组类型适配
    return new ParameterHandler.Field<>(name, converter, encoded).array();
  } else {
    Converter<?, String> converter = retrofit.stringConverter(type, annotations);
    // new一个ParameterHandler.Field
    return new ParameterHandler.Field<>(name, converter, encoded);
  }
}

进入ParameterHandler.Field查看定义:

static final class Field<T> extends ParameterHandler<T> {
  // 移除构造函数等无关代码

  @Override
  void apply(RequestBuilder builder, @Nullable T value) throws IOException {
    
    String fieldValue = valueConverter.convert(value);
    // 最终转到了RequestBuilder#addFormField方法
    builder.addFormField(name, fieldValue, encoded);
  }
}

继续查看RequestBuilder#addFormField

void addFormField(String name, String value, boolean encoded) {
  if (encoded) {
    formBuilder.addEncoded(name, value);
  } else {
    formBuilder.add(name, value);
  }
}

最终使用了okhttp3FormBody.Builder进行form的field添加。


2.3.3.1.13 FieldMap

使用方式:

@POST("/")
Call<String> get21(@FieldMap Map<String, String> headerMap);

Field的区别就在于参数传递的差别

解析代码:

else if (annotation instanceof FieldMap) {
  // ... 移除了一些校验代码
  Class<?> rawParameterType = Utils.getRawType(type);
  Type mapType = Utils.getSupertype(type, rawParameterType, Map.class);
  ParameterizedType parameterizedType = (ParameterizedType) mapType;
  // 获取key value类型
  Type keyType = Utils.getParameterUpperBound(0, parameterizedType);
  Type valueType = Utils.getParameterUpperBound(1, parameterizedType);
  Converter<?, String> valueConverter = retrofit.stringConverter(valueType, annotations);
	// 设置标志位
  gotField = true;
  // mew ParameterHandler.FieldMap
  return new ParameterHandler.FieldMap<>(
    method, p, valueConverter, ((FieldMap) annotation).encoded());
}

继续查看ParameterHandler.FieldMap定义:

static final class FieldMap<T> extends ParameterHandler<Map<String, T>> {
 // 构造函数等定义

  @Override
  void apply(RequestBuilder builder, @Nullable Map<String, T> value) throws IOException {
   

    for (Map.Entry<String, T> entry : value.entrySet()) {
      // 移除了一些校验代码 保留核心逻辑
      String entryKey = entry.getKey();
      T entryValue = entry.getValue();
      
      String fieldEntry = valueConverter.convert(entryValue);

      builder.addFormField(entryKey, fieldEntry, encoded);
    }
  }
}

同样的,转到了RequestBuilder#addFormField执行。


2.3.3.1.14 Part

使用方式:

@POST("/")
Call<String> get22(@Part("file") RequestBody request);

@POST("/")
Call<String> get22(@Part Part part);

一般是用来文件上传的请求方式。且@Part注解和MultipartBody.Part对象不能同时使用

解析代码:

else if (annotation instanceof Part) {
  if (!isMultipart) {
    // Part一定要跟Multipart注解 否则抛出异常
  }
  Part part = (Part) annotation;
  gotPart = true;

  String partName = part.value();
  Class<?> rawParameterType = Utils.getRawType(type);
  if (partName.isEmpty()) {
    // 未设置Part注解的名称的情况下 需要参数类型为 MultipartBody.Part
    
    if (Iterable.class.isAssignableFrom(rawParameterType)) {
      
      ParameterizedType parameterizedType = (ParameterizedType) type;
      Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
      if (!MultipartBody.Part.class.isAssignableFrom(Utils.getRawType(iterableType))) {
        // @Part注解对应的参数必须是Part类型 否则抛出异常
      }
      // 使用ParameterHandler.RawPart 这是一个单例类 内部因为不需要关心处理具体参数是啥,所以就成了一个工具类
      return ParameterHandler.RawPart.INSTANCE.iterable();
    } else if (rawParameterType.isArray()) {
      Class<?> arrayComponentType = rawParameterType.getComponentType();
      if (!MultipartBody.Part.class.isAssignableFrom(arrayComponentType)) {
        // @Part注解对应的参数必须是Part类型 否则抛出异常
      }
      // 同上 给一个处理MultipartBody.Part类型的处理类
      return ParameterHandler.RawPart.INSTANCE.array();
    } else if (MultipartBody.Part.class.isAssignableFrom(rawParameterType)) {
      // 同上
      return ParameterHandler.RawPart.INSTANCE;
    } else {
      // @Part注解对应的参数必须是Part类型 否则抛出异常
    }
  } else {
    // Part注解上的name 参数不为空
    // 需要设置header
    Headers headers =
      Headers.of(
      "Content-Disposition",
      "form-data; name=\"" + partName + "\"",
      "Content-Transfer-Encoding",
      part.encoding());

    if (Iterable.class.isAssignableFrom(rawParameterType)) {
      
      ParameterizedType parameterizedType = (ParameterizedType) type;
      Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
      if (MultipartBody.Part.class.isAssignableFrom(Utils.getRawType(iterableType))) {
      // 校验参数类型 如果@Part注解设置了name 则参数类型不能是MultipartBody.Part 两个不能通用 抛出异常
      }
      
      // 这里跟之前不一样的地方在于 使用了RequestBodyConverter 而不是StringConverter
      Converter<?, RequestBody> converter =
        retrofit.requestBodyConverter(iterableType, annotations, methodAnnotations);
      // 构建ParameterHandler.Part实例
      return new ParameterHandler.Part<>(method, p, headers, converter).iterable();
    } else if (rawParameterType.isArray()) {
      Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
      if (MultipartBody.Part.class.isAssignableFrom(arrayComponentType)) {
	      // 校验参数类型 如果@Part注解设置了name 则参数类型不能是MultipartBody.Part 两个不能通用
      }
      
      // 使用了RequestBodyConverter 
      Converter<?, RequestBody> converter =
        retrofit.requestBodyConverter(arrayComponentType, annotations, methodAnnotations);
      
      return new ParameterHandler.Part<>(method, p, headers, converter).array();
    } else if (MultipartBody.Part.class.isAssignableFrom(rawParameterType)) {
      // 校验参数类型 如果@Part注解设置了name 则参数类型不能是MultipartBody.Part 抛出异常
    } else {
      Converter<?, RequestBody> converter =
        retrofit.requestBodyConverter(type, annotations, methodAnnotations);
      return new ParameterHandler.Part<>(method, p, headers, converter);
    }
  }
}

@Part的解析代码有一个特殊的地方在于@Part的使用规则是如果设置了@Part注解的name,则参数不能是Part类型。

同时,针对Part类型的参数,直接简单的使用ParameterHandler.RawPart单个实例处理apple请求:

static final class RawPart extends ParameterHandler<MultipartBody.Part> {
  static final RawPart INSTANCE = new RawPart();

  @Override
  void apply(RequestBuilder builder, @Nullable MultipartBody.Part value) {
    builder.addPart(value);
  }
}

进入RequestBuilder#addPart查看:

void addPart(MultipartBody.Part part) {
  multipartBuilder.addPart(part);
}

而对于非Part类型的参数,则需要提供RequestBoddConvert进行对象转换成RequestBody类型:

static final class Part<T> extends ParameterHandler<T> {
 // 略过构造函数等代码

  @Override
  void apply(RequestBuilder builder, @Nullable T value) {

    RequestBody body;
    try {
      // 使用RequestBodyConvert进行对象转换
      body = converter.convert(value);
    } catch (IOException e) {
      throw Utils.parameterError(method, p, "Unable to convert " + value + " to RequestBody", e);
    }
    builder.addPart(headers, body);
  }
}

转换完成之后,调用RequestBuilder#addPart方法,内部最终也是构建成一个Part,同上面一样。

2.3.3.1.15 PartMap

使用方式:

@POST("/")
Call<String> get24(@PartMap Map<String, RequestBody> partMap);

解析代码同Part的差别不大,无非是一个是1 一个是多而已。

2.3.3.1.16 Body

使用方式:

@GET("/")
Call<String> get3(@Body Data data);

解析代码:

else if (annotation instanceof Body) {
	
  // 如果是@Body注解 则肯定不能使用 FormEncoded和Multipart
  if (isFormEncoded || isMultipart) {
    throw parameterError(
      method, p, "@Body parameters cannot be used with form or multi-part encoding.");
  }
  // 避免重复Body
  if (gotBody) {
    throw parameterError(method, p, "Multiple @Body method annotations found.");
  }

  Converter<?, RequestBody> converter;
  try {
    // 获取requestBodyConverter
    converter = retrofit.requestBodyConverter(type, annotations, methodAnnotations);
  } catch (RuntimeException e) {
    // Wide exception range because factories are user code.
    throw parameterError(method, e, p, "Unable to create @Body converter for %s", type);
  }
  gotBody = true;
  // 得到ParameterHandler.Body
  return new ParameterHandler.Body<>(method, p, converter);

}

在实际的场景当中,我们使用Body时,都是以application/json方式进行数据传入,那么就需要一个转换器将对象转换为json。最后构建一个ParameterHandler.Body

static final class Body<T> extends ParameterHandler<T> {

  @Override
  void apply(RequestBuilder builder, @Nullable T value) {
    
    RequestBody body;
    try {
      // 数据转换
      body = converter.convert(value);
    } catch (IOException e) {
      throw Utils.parameterError(method, e, p, "Unable to convert " + value + " to RequestBody");
    }
    // 调用RequestBuilder#setBody
    builder.setBody(body);
  }
}

进入RequestBuilder#setBody

void setBody(RequestBody body) {
  this.body = body;
}
2.3.3.1.17 Tag

使用方式:

 @GET("/")
Call<String> get25(@Tag String tag);

解析代码:

 else if (annotation instanceof Tag) {

   Class<?> tagType = Utils.getRawType(type);
   for (int i = p - 1; i >= 0; i--) {
     ParameterHandler<?> otherHandler = parameterHandlers[i];
     if (otherHandler instanceof ParameterHandler.Tag
         && ((ParameterHandler.Tag) otherHandler).cls.equals(tagType)) {
       // 避免重复
       throw parameterError(
         method,
         p,
         "@Tag type "
         + tagType.getName()
         + " is duplicate of parameter #"
         + (i + 1)
         + " and would always overwrite its value.");
     }
   }
   
   return new ParameterHandler.Tag<>(tagType);

进入ParameterHandler.Tag:

static final class Tag<T> extends ParameterHandler<T> {
  @Override
  void apply(RequestBuilder builder, @Nullable T value) {
    builder.addTag(cls, value);
  }
}

至此,所有的HTTP相关注解全部解析完成。

这一部分,解析不同注解的代码思路基本相同,除去规则校验之外,就是将注解信息等元数据转换成ParameterHandler对象,等待RequestBuild进行调用时,将对应参数根据生成的ParameterHandler,以不同的规则将参数转换成RequestBuilder所能使用的参数。

最后,回到RequestFactory.Builder#build方法,执行关键的new RequestFactory(this);就得到了我们需要的承载了创建Request的工厂对象:

final class RequestFactory {
	// 每个Service的方法
  private final Method method;
  // base url
  private final HttpUrl baseUrl;
  // http方法 get post
  final String httpMethod;
  // 相对url 
  private final @Nullable String relativeUrl;
  // headers
  private final @Nullable Headers headers;
  // contentType
  private final @Nullable MediaType contentType;
  // 是否有body
  private final boolean hasBody;
  // 是否是FormEncoded请求
  private final boolean isFormEncoded;
  // 是否是Multipart请求
  private final boolean isMultipart;
  // 每个参数上的注解对应的Handler
  private final ParameterHandler<?>[] parameterHandlers;
  final boolean isKotlinSuspendFunction;

  RequestFactory(Builder builder) {
    method = builder.method;
    baseUrl = builder.retrofit.baseUrl;
    httpMethod = builder.httpMethod;
    relativeUrl = builder.relativeUrl;
    headers = builder.headers;
    contentType = builder.contentType;
    hasBody = builder.hasBody;
    isFormEncoded = builder.isFormEncoded;
    isMultipart = builder.isMultipart;
    parameterHandlers = builder.parameterHandlers;
    isKotlinSuspendFunction = builder.isKotlinSuspendFunction;
  }
}

得到了代表创建请求的RequestFactory(请求工厂)之后,在后续的流程里,会使用工厂创建请求,本着用到再说的规则,在创建请求时,继续梳理RequestFactory的相关代码。

先回顾一下到此为止,针对一个如下的Service:

public interface BaiduApi {
    @GET("/")
    Call<String> get1(@Query("aaa") String args);
}

我们做了哪些解析?

1)方法上的注解解析。得到了请求的相对路径、请求方式等等

2)方法参数的注解、参数解析。得到了该请求所需要的参数信息以及如何将Java方法参数转换为Http请求的处理类

以上两部分信息都被包装在了RequestFactory中。

那么,剩余未处理的也就明朗起来了:方法返回值的解析

接下来围绕着这个目标,来深入到HttpServiceMethod#parseAnnotations。

2.3.4 HttpServiceMethod#parseAnnotations

ServiceMethod方法内部,调用RequestFactory#parseAnnotations之后,得到代表创建请求的RequestFactory,随后转到了HttpServiceMethod#parseAnnotations进行剩余的注解解析处理。

由于上面已经贴过HttpServiceMethod#parseAnnotations的代码,所以这里就个代码骨架,移除一些判断以及kotlin的支持:

static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    // 获取方法的注解
    Annotation[] annotations = method.getAnnotations();
    // 定义adapter的类型
    Type adapterType = method.getGenericReturnType();
    
    // 获取CallAdapter
    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);

    // CallAdapter的responseType
    Type responseType = callAdapter.responseType();

    // 获取responseConverter
    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);

    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    // 返回一个CallAdapted实例
    return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);

可以看到,整个流程的核心思路分为三步:1)获取CallAdapter;2)获取responseConverter;3:创建CallAdapted实例。接下来先简单讲一下三个组件的获取方式,下一章详细讲解三个组件的职责。

2.3.4.1 HttpServiceMethod#createCallAdapter

关于CallAdapter的详细定义,可以查看下面的章节,这里先简单的梳理一下获取的流程

首先第一步是获取CallAdapter,通过查看代码:

private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
  Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {
  try {
    return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
  } catch (RuntimeException e) { 
    throw methodError(method, e, "Unable to create call adapter for %s", returnType);
  }
}

可以得知,内部跳转到了Retrofit.callAdapter,而Retrofit.callAdapter会跳转到Retrofit#nextCallAdapter

public CallAdapter<?, ?> nextCallAdapter(
  @Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {

  int start = callAdapterFactories.indexOf(skipPast) + 1;
  for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
    // 迭代创建Retrofit时设置的AdapterFactory 找到匹配的第一个adapter
    CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
    if (adapter != null) {
      return adapter;
    }
  }
  // 无法找到适配当前方法返回值的CallAdapter 抛异常
}

在这个阶段,Retrofit会根据Service的方法的返回类型,迭代所有的AdapterFactory,调用对应的get方法。

有了Adapter之后,就明确了Adapter能够处理的responseType,就可以通过responseType来获取对应的ResponseConvert

2.3.4.1 HttpServiceMethod#createResponseConverter

查看获取代码:

private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter(
  Retrofit retrofit, Method method, Type responseType) {
  Annotation[] annotations = method.getAnnotations();
  try {
    // 跳到了Retrofit#responseBodyConverter
    return retrofit.responseBodyConverter(responseType, annotations);
  } catch (RuntimeException e) { 
    throw methodError(method, e, "Unable to create converter for %s", responseType);
  }
}

代码内部跳到了Retrofit#responseBodyConverter,最终会依赖于Retrofit#nextResponseBodyConverter

public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
  @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {

  int start = converterFactories.indexOf(skipPast) + 1;
  for (int i = start, count = converterFactories.size(); i < count; i++) {
    Converter<ResponseBody, ?> converter =
      converterFactories.get(i).responseBodyConverter(type, annotations, this);
    if (converter != null) {
      // 强转
      return (Converter<ResponseBody, T>) converter;
    }
  }
 // 未找到 抛异常
}

具体的获取类型同CallAdpater差不多,根据responseType,迭代所有的converterFactory找到合适的进行返回。

有了CallAdapter(适配Service返回对象)、ResponseConvert(适配Service返回的业务对象),之后,就是进行整合。而CallAdapted就是起到组合、调用适配的功能。所以最后一步,就是创建一个CallAdapted

return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);

至此,整个初始化流程就结束了,回到2.3.1,拿到CallAdaptedServiceMethod的子类)放入缓存,接下来进入到真正的invoke阶段。

Retrofit 源码深度解析-(3)Invoke

posted @ 2021-09-14 14:54  卡卡一点都不卡  阅读(110)  评论(0编辑  收藏  举报