携手创作,共同生长!这是我参与「日新计划 8 月更文应战」的第1天,点击查看活动概况

Retrofit源码系列文章:

  • 挖一挖Retrofit源码(一)
  • 挖一挖Retrofit源码(二)
  • Retrofit之CallAdapter解析
  • Retrofit之自定义CallAdapter
  • Retrofit之Converter解析

简介

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生成动态署理目标的逻辑,那动态署理是怎样进行网络恳求的和回调又是怎么处理的呢?下一篇将持续分析。