挖一挖Retrofit源码(一)

553 阅读6分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情

Retrofit源码系列文章:

简介

Retrofit是一个基于OkHttp的网络请求框架,对OkHttp的请求和结果进行处理,Retrofit仅负责网络请求接口的封装并自动生成实际网络请求的代码,而网络请求的工作本质上是OkHttp完成的。

应用发起网络请求后,实际上是使用 Retrofit 接口层封装请求参数、Header、Url等信息,之后由OkHttp完成后续的请求操作,OkHttp将服务器返回的原始数据交给Retrofit,Retrofit根据用户的需求对结果进行解析。

PS:本文基于Retrofit版本2.8.0

源码解析

1. 创建Retrofit实例

val retrofit = Retrofit.Builder()
            .baseUrl("https://test.com")
            .addConverterFactory(GsonConverterFactory.create())
            .build()

Retrofit实例是使用建造者模式通过Builder类创建的,并初始化一些配置项,下面将对创建Retrofit实例进行详细分析。

1.1 Retrofit类

public final class Retrofit {
  private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();


  final okhttp3.Call.Factory callFactory; //生产网络请求器(Call)的工厂,默认使用OkHttp
  final HttpUrl baseUrl; //url地址
  final List<Converter.Factory> converterFactories; //数据转换器(converter)的工厂List
  final List<CallAdapter.Factory> callAdapterFactories; //生产网络请求适配器(CallAdapter)的工厂List
  final @Nullable Executor callbackExecutor; //回调方法执行器
  final boolean validateEagerly; //是否提前对业务接口中的注解进行验证转换的标志位


  Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
      List<Converter.Factory> converterFactories, List<CallAdapter.Factory> callAdapterFactories,
      @Nullable Executor callbackExecutor, boolean validateEagerly) {
    this.callFactory = callFactory;
    this.baseUrl = baseUrl;
    this.converterFactories = converterFactories; // Copy+unmodifiable at call site.
    this.callAdapterFactories = callAdapterFactories; // Copy+unmodifiable at call site.
    this.callbackExecutor = callbackExecutor;
    this.validateEagerly = validateEagerly;
  }
  //省略其他代码
  ......
}

其中callFactory、converterFactories、callAdapterFactories体现了工厂模式,使用者不需要关心具体参数就可以实例化出所需要的类。

1.2 Builder类

public static final class Builder {
    private final Platform platform;
    private @Nullable okhttp3.Call.Factory callFactory;
    private @Nullable HttpUrl baseUrl;
    private final List<Converter.Factory> converterFactories = new ArrayList<>();
    private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
    private @Nullable Executor callbackExecutor;
    private boolean validateEagerly;


    //①Builder的有参构造函数
    Builder(Platform platform) {
      this.platform = platform;
    }


    //②Builder的无参构造函数
    public Builder() {
      this(Platform.get());
    }
    ......
}

可以看出Builder类的成员变量和Retrofit类的是对应的,所以Retrofit类的成员变量基本上是通过Builder类来配置。

代码里①接收了Platform对象并设进Builder类的Platform,而②则是用this调用了自己的有参构造函数①并通过调用Platform.get()传入Platform对象,即Builder的构造函数中检测了当前的运行平台。

1.3 addConverterFactory方法

public Builder addConverterFactory(Converter.Factory factory) {
      converterFactories.add(Objects.requireNonNull(factory, "factory == null"));
      return this;
}

前面创建Retrofit实例的时候是把GsonConverterFactory.create()传进了addConverterFactory方法,而GsonConverterFactory.create()实际上是创建并返回了一个含有Gson对象实例的GsonConverterFactory,即指定Retrofit使用Gson进行解析数据,也可以使用其他解析方式(如Json、XML或Protocobuf)或者可以使用自定义数据解析器(必须继承Converter.Factory)。addCallAdapterFactory方法也是类似的,可以添加Retrofit内置的CallAdapterFactory,也可以使用自定义的适配器。

1.4 build方法

在创建Retrofit.Builder对象并进行自定义配置后,我们就要调用build方法来构造出Retrofit对象了,下面来看看build()里干了什么:

public Retrofit build() {
      //必须要配置baseUrl
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }


      //配置网络请求执行器,若无指定则默认使用OkHttp
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }


      //配置回调方法执行器,Android平台下默认为MainThreadExecutor
      //MainThreadExecutor的作用:切换线程(子->>主线程),并在主线程(UI线程)中执行回调方法
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }


      // Make a defensive copy of the adapters and add the default Call adapter.
      //配置网络请求适配器工厂,将默认适配器工厂DefaultCallAdapterFactory添加至List末尾
      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.
      //首先添加默认的BuiltInConverters,最后添加检测平台环境时默认返回的数据转换器OptionalConverterFactory
      converterFactories.add(new BuiltInConverters());
      converterFactories.addAll(this.converterFactories);
      converterFactories.addAll(platform.defaultConverterFactories());


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

可以看到在build()中做了:检查配置、设置默认配置、创建Retrofit对象,而且在执行build()之前只有baseUrl()是必须调用来设置访问地址的,其余方法则是可选的,没有指定就使用默认配置。另外:

  • callFactory负责创建HTTP请求,HTTP请求被抽象为了okhttp3.Call类,它表示一个已经准备好,可以随时执行的HTTP请求
  • CallAdapter负责把服务器的原始返回数据封装成Retrofit的Call对象(注意和okhttp3.Call区分开来),通过Call发起HTTP请求,并把从服务器拿到的数据(通过okhttp3.Call实现)转换为接口方法声明的返回类型T(通过Converter<F, T> 实现)

1.5 总结

Retrofit创建实例时主要涉及了以下的配置项:

  • 网络请求地址baseUrl
  • 网络请求执行器工厂callFactory:默认使用OkHttpClient,通过OkHttp处理后续网络请求和响应
  • 回调方法执行器callbackExecutor:默认使用MainThreadExecutor
  • 网络请求适配器工厂集合callAdapterFactories:默认添加DefaultCallAdapterFactory
  • 数据转换器工厂集合converterFactories:默认添加BuiltInConverters和OptionalConverterFactory,BuiltInConverters直接取对应的值并未转换,可以通过设置GsonConverterFactory来用Gson解析json数据

由于使用了建造者模式,所以创建Retrofit实例时并不需要关心配置细节。

2. 创建网络请求接口实例

//定义网络请求的接口类
interface TestApi {
    @GET("/.../...")
    fun getDataA(): Call<DataBean> //①不使用协程
    
    @GET("/.../...")
    suspend fun getDataB(): DataBean //②使用协程
}


//创建网络请求接口实例
val testApi = retrofit.create(TestApi::class.java)


//调用接口方法①
fun getDataA() {
        testApi.getDataA().enqueue(object : Callback<DataBean> {
            override fun onResponse(
                call: Call<DataBean>,
                response: Response<DataBean>
            ) {
                //成功逻辑
            }


            override fun onFailure(call: Call<DataBean>, t: Throwable) {
                //失败逻辑
            }
        })
}
//调用接口方法②
suspend fun getDataB() {
        try {
            testApi.getDataB()
            //成功逻辑
        } catch (e: Exception) {
            //失败逻辑
        }
}

可以看到请求接口里的请求方法类型及请求url的后半部分是通过注解来标注的,而DataBean是该方法的返回类型(一个自定义的Data类)

另外,在没有给Retrofit添加任何CallAdapterFactory的情况下:

  • 接口方法①的返回类型就必须是Call<?>,不能为其他类型;
  • 接口方法②由于用了suspend关键字,挂起了之后就可以无需使用Call类型返回结果,而是直接返回数据类对象。

接口创建完之后就是调用Retrofit的create方法来生成接口的动态代理对象,下面就来看看具体是怎么实现动态代理的。

2.1 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 (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            //是默认方法则直接执行默认方法
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            //获取方法的对应ServiceMethod对象并调用invoke方法
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });
  }

①处的方法除了校验接口之外,还对是否提前解析接口中的所有方法进行了判断:

private void validateServiceInterface(Class<?> service) {
    if (!service.isInterface()) {
      throw new IllegalArgumentException("API declarations must be interfaces.");
    }


    Deque<Class<?>> check = new ArrayDeque<>(1);
    check.add(service);
    ......//验证接口泛型参数及接口类型


     //如果设置了预解析则提前解析接口中的所有方法
     if (validateEagerly) {
      Platform platform = Platform.get();
      for (Method method : service.getDeclaredMethods()) {
        if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
          loadServiceMethod(method);
        }
      }
    }
  }

如果初始化Retrofit实例的时候设置了预解析,就会提前给接口中的每个方法解析生成对应的一个ServiceMethod对象并存入缓存,否则就调用方法的时候再动态解析,具体是怎么解析的看loadServiceMethod这个方法(后面会说明)

在create方法中主要的代码就是②处的Proxy.newProxyInstance,当把请求接口类传进create里的时候就会动态生成并返回一个代理对象,而接口方法被调用的时候实际上是由动态代理对象将方法转发到InvocationHandler的invoke方法中处理。因为实际调用的接口方法不是默认方法,那真正调用到的就是loadServiceMethod(method).invoke(args != null ? args : emptyArgs),这也是后续分析的关键入口。

2.2 loadServiceMethod方法

ServiceMethod<?> loadServiceMethod(Method method) {
    //从缓存中获取
    ServiceMethod<?> result = serviceMethodCache.get(method);
    if (result != null) return result;


    //加锁,创建该方法的ServiceMethod对象并存入缓存
    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = ServiceMethod.parseAnnotations(this, method);
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

接口方法传进loadServiceMethod后优先是从缓存中查对应的ServiceMethod对象,获取到了就直接返回,否则加锁后创建这个方法的ServiceMethod对象,以method为主键存入一个叫serviceMethodCache的map中。

可以看出来同一个接口的方法只会解析一次,每一个调用过的方法都会存在对应的ServiceMethod对象,因为建接口实例的时候传进的是class对象(TestApi::class.java),class对象在进程内单例的,所以获取到的同一个method也是单例的,因此这里的缓存有效。

这段代码主要是为了拿到一个ServiceMethod对象,而生成ServiceMethod对象是调用了ServiceMethod的parseAnnotations方法,ServiceMethod里面到底是什么东东,parseAnnotations方法具体干了什么,下面继续来扒一扒。

2.3 ServiceMethod类

abstract class ServiceMethod<T> {
  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.");
    }


    //生成并返回HttpServiceMethod对象
    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }


  abstract @Nullable T invoke(Object[] args);
}

回看2.1中获取的ServiceMethod对象实际上是这里的HttpServiceMethod对象,调用链路为loadServiceMethod -> ServiceMethod.parseAnnotations -> HttpServiceMethod.parseAnnotations,继续往下看HttpServiceMethod的parseAnnotations方法。

2.4 HttpServiceMethod类parseAnnotations方法

static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
    boolean continuationWantsResponse = false;
    boolean continuationBodyNullable = false;


    Annotation[] annotations = method.getAnnotations();
    Type adapterType;
    if (isKotlinSuspendFunction) {
      //Kotlin协程检测
      ......
      adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
      annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
    } else {
      //获取方法返回类型
      adapterType = method.getGenericReturnType();
    }


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


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


    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    if (!isKotlinSuspendFunction) {
      return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
    } else if (continuationWantsResponse) {
      //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
      return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForResponse<>(requestFactory,
          callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
    } else {
      //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
      return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForBody<>(requestFactory,
          callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
          continuationBodyNullable);
    }
  }

parseAnnotations方法最后返回的是HttpServiceMethod对象,如果是非挂起方法则直接返回CallAdapted,挂起方法并且返回类型为Response则返回SuspendForResponse,否则返回SuspendForBody。

现在了解了Retrofit生成动态代理对象的逻辑,那动态代理是怎么进行网络请求的和回调又是如何处理的呢?下一篇将继续分析。