Retrofit原理

概论

当前版本com.squareup.retrofit2:retrofit:2.9.0

虽然okhttp很好用,但是开发者所需要关心的细节太多了,所以square又开发了retrofit简化流程。

retrofit主要使用流程如下:

interface GithubService {

    @GET("users/{user}/repos")
    fun listRepos(@Path("user") user: String): Call<List<String>>
}

val retrofit = Retrofit.Builder()
  .baseUrl("https://api.github.com/")
  .build()

val service = retrofit.create(GithubService::class.java)

val repos = service.listRepos("octocat")

过程非常简单,但是有一些问题:

  1. 如何做到将接口转化为实现类?
  2. 如何将retrofit调用转化为okhttp调用?
  3. 如何从注解中获取信息填充到request?
  4. 如何将response转化为相应的实体类?

生成实现类

现在有target这样一个类,target有方法targetFunction;现在有这样的需求,在不修改target类源代码的前提下,在targetFunction真正执行之前或者之后添加一些行为;由于不能修改target的源代码,所以必须要新建一个类proxy,去调用targetFunction方法,并且添加行为;

这种设计模式被称为代理模式,根据proxy字节码文件是否先于编译期存在,分为 静态代理动态代理

静态代理

proxy声明和target一样的接口,并且拥有一个target字段,然后再接口实现中调用target的方法,并添加行为;

具体代码如下:

interface GithubService{
	fun listRepos(user: String): List<String>
}

class Target : GithubService{

    override fun listRepos(user: String): List<String>{
    	return listOf()
    }
}

class Proxy : GithubService{
	private val target = Target()
	
	override fun listRepos(user: String): List<String>{
		println("before invocation")
		val result = target.listRepos(user)
		println("after invocation")
		return result
	}
}

动态代理

静态代理的proxy可以针对每个方法去提供特定实现,动态代理想要做到这一点,就需要知道当前在执行哪个方法,根据方法签名去提供特定实现;

所以动态代理需要三个东西:

  1. 约定实现的接口
  2. 针对接口方法提供实现的InvocationHandler
  3. 该接口的原本实现类(可有可无)

具体代码如下:

interface GithubService{
	fun listRepos(user: String): List<String>
}

class Target : GithubService{

    override fun listRepos(user: String): List<String>{
    	return listOf()
    }
}

class ProxyInvocationHandler(val target: Any) : InvocationHandler{
    override fun invoke(proxy: Any?, method: Method?, args: Array<out Any>?): Any {
        println("before invocation")
        val result = method?.invoke(target, args)
        println("after invocation")
        return result
    }
}

fun main(){
    val invocationHandler = ProxyInvocationHandler(Target())
    val proxy = Proxy.newProxyInstance(
        GithubService::class.java.getClassLoader(),
        arrayOf(GithubService::class.java),
        invocationHandler
    )
    
    proxy.listRepos("octocat")
}

更加具体的过程,请查看这篇文章

实现过程

Retrofit的构造过程

  1. Retrofit.Builder

builderretrofit的建造者,其重要字段如下:

// 根据当前虚拟机的名称确定平台
// 提供CallAdapterFactory和ConverterFactory
private final Platform platform;
// 根据request发起请求的客户端,默认为OkHttpClient
private @Nullable okhttp3.Call.Factory callFactory;
// 域名
private @Nullable HttpUrl baseUrl;
// 完成实体类到requestBody的转换,responseBody到实体类的转换的工厂
private final List<Converter.Factory> converterFactories = new ArrayList<>();
// 根据返回值决定Call的执行方式的工厂
private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
// 回调执行的位置
private @Nullable Executor callbackExecutor;
// 如果为true,retrofit.create()会完成所有方法的ServiceMethod的创建
private boolean validateEagerly;

建造过程:

public Retrofit build() {
    // 必须要定义域名
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }
	
    // 默认由OkHttpClient发起请求
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }

    // 内部调用Handler在主线程执行回调
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      // 先匹配自定义的工厂
      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);
    }

CallAdapter.Factory

这个类只有一个抽象方法:

根据返回值返回CallAdapter
public abstract @Nullable CallAdapter<?, ?> get(
        Type returnType, Annotation[] annotations, Retrofit retrofit);

默认有两个实现类CompletableFutureCallAdapterFactoryDefaultCallAdapterFactory

该方法在DefaultCallAdapterFactory中的实现如下:

  @Override
  public @Nullable CallAdapter<?, ?> get(
      Type returnType, Annotation[] annotations, Retrofit retrofit) {
    // 只适配Call<T>
    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>");
    }
      
    // 获取泛型上界
    final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);
	// 根据注解获取executor
    final Executor executor =
        Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
            ? null
            : callbackExecutor;

    // 匿名对象
    return new CallAdapter<Object, Call<?>>() {
      @Override
      public Type responseType() {
        return responseType;
      }

      @Override
      public Call<Object> adapt(Call<Object> call) {
        return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
      }
    };
  }

CompletableFutureCallAdapterFactory的实现也是相似的,不在赘述;

CallAdapter

// R 代表 ResponseBody 对应的实体类
// T 代表 Call 的代理类,有两种情况
// 1. Call<R>本身
// 2. CompletableFuture<R>
public interface CallAdapter<R, T> {
  /**
   * 在responseBody转化为实体类时会调用,一般返回R代表的类型
   */
  Type responseType();

  /**
   * 根据call返回T
   */
  T adapt(Call<R> call);
  }

Converter.Factory

// 定义了RequestBody和ResponseBody转换的函数
abstract class Factory {
  
  // 由ResponseBody转化为对应实体类
  public @Nullable Converter<ResponseBody, ?> responseBodyConverter(
      Type type, Annotation[] annotations, Retrofit retrofit) {
    return null;
  }

  /**
   * 将由 @Body,@Part,@PartMap注解的参数转化为RequestBody
   */
  public @Nullable Converter<?, RequestBody> requestBodyConverter(
      Type type,
      Annotation[] parameterAnnotations,
      Annotation[] methodAnnotations,
      Retrofit retrofit) {
    return null;
  }

  /**
   * 对应类型转化为String
   */
  public @Nullable Converter<?, String> stringConverter(
      Type type, Annotation[] annotations, Retrofit retrofit) {
    return null;
  }
 }

默认实现有BuiltInConvertersOptionalConverterFactory

Converter

// 定义了一个从F转化到T的函数
public interface Converter<F, T> {
  @Nullable
  T convert(F value) throws IOException;
 }

一共有七个实现类,分布在BuiltInConvertersOptionalConverterFactory中,实现也都很简单,不再说明;

InvocationHandler

InvocationHandler包含了对每个接口方法的处理,代码如下:

 @Override
 public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
     throws Throwable {
   // 该方法在Object类中声明,则直接调用
   if (method.getDeclaringClass() == Object.class) {
     return method.invoke(this, args);
   }
   args = args != null ? args : emptyArgs;
   // 如果该方法是default方法(在Java8里添加),则调用default方法;
   // 否则生成ServiceMethod调用invoke方法;
   return platform.isDefaultMethod(method)
       ? platform.invokeDefaultMethod(method, service, proxy, args)
       : loadServiceMethod(method).invoke(args);
 }

ServiceMethod

ServiceMethod是一个抽象类,代码如下:

abstract class ServiceMethod<T> {
  // 处理注解,生成ServiceMethod的实现类
  static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    // 处理注解,获得关于request的信息
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);

    Type returnType = method.getGenericReturnType();
    if (Utils.hasUnresolvableType(returnType)) {
      throw methodError(
          method,
          "Method return type must not include a type variable or wildcard: %s",
          returnType);
    }
    if (returnType == void.class) {
      throw methodError(method, "Service methods cannot return void.");
    }

    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }

  // 传入参数,调用接口方法,返回Call<R>,或CompletableFuture<R>
  abstract @Nullable T invoke(Object[] args);
}

ServiceMethod有一个抽象子类HttpServiceMethod,重要字段如下:

// 保存request的信息
private final RequestFactory requestFactory;
// 真正发起请求的客户端
private final okhttp3.Call.Factory callFactory;
// 将ResponseBody转化为指定类型
private final Converter<ResponseBody, ResponseT> responseConverter;

HttpServiceMethod实现了invoke抽象方法,并且添加了一个新的抽象方法;

@Override
final @Nullable ReturnT invoke(Object[] args) {
  Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
  return adapt(call, args);
}

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

HttpServiceMethod又有三个子类:CallAdaptedSuspendForResponseSuspendForBody

根据isKotlinSuspendFunction分为两类,后面一类支持协程,isKotlinSuspendFunction来自RequestFactory,具体过程稍后说明;

CallAdapted代码如下:

    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) {
      return callAdapter.adapt(call);
    }
  }

只是简单调用了CallAdapter进行转换;

RequestFactory

RequestFactory可以算是一个工具类,从Method中获取所有的注解,然后将注解中的信息分离出来;

其主要工作都是RequestFactory.Builder完成的,处理两类注解:方法注解和参数注解;具体细节请看源码,但是有几点需要提醒:

  1. 方法注解主要是对相对路径的完善,也就是报文中的请求行;
  2. 参数注解主要是对请求头和请求体的完善;
  3. 对于最后一个参数,会进行特殊处理,判断其类型是不是Continuation,然后为isKotlinSuspendFunction赋值;为什么是最后一个参数?是因为kotlin中的挂起函数,在编译过程中,会在函数的参数列表中添加一个Continuation以实现其功能;

结论

其实还有好多细节没有讲清,比如RequestFacotry的具体工作过程、代码内各种关于Type的判断等等,但是对于理解Retrofit整体工作过程是足够了;

总结一下,Retrofit的工作过程如下:

  1. 配置Retrofit,获得CallAdapter.Factory列表和Converter.Factory列表等其他信息;
  2. 通过动态代理生成代理类;
  3. 通过RequestFactory获得request所需信息;
  4. 最终通过ServiceMethod的子类发送请求;
posted @ 2021-02-27 14:33  ijkzen  阅读(440)  评论(0编辑  收藏  举报