Retrofit源码解析(三)

Retrofit源码解析(一)
Retrofit源码解析(二)

前两篇介绍了retrofit与okhttp的关系以及retrofit的内部属性组成,这一遍正式开始剖析retrofit发送一个网络请求的全过程。我们使用最简单的方式构建retrofit,没有搭配RxJava2CallAdapterFactory也没有设置GsonConvertFactory,看看最原汁原味的retrofit是如何工作的。

一、retrofit构建

val retrofit = Retrofit.Builder().baseUrl("http://www.base.com/").build()

先来看retrofit.Builder的构建过程,最终调用了Builder的build()方法:

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);
    }

在默认情况下:

callFactory默认情况下直接赋值为OkHttpClient对象。
callbackExecutor是retrofit提供的在主线程执行的线程池。

callAdapterFactories列表中添加了一个retrofit提供的默认实现DefaultCallAdapterFactory,这个类的具体代码后边再详细说。但是要注意列表中元素的添加顺序,是先把我们自定义的factory放在列表的前边,DefaultCallAdapterFactory放在最后。

converterFactories列表中添加了一个默认实现BuiltInConverters对象。但是注意添加的顺序与callAdapterFactories是正好相反的。(retrofit的这两个列表添加的默认实现顺序是不一样的,其实是有道理的,此处先卖个关子)

二、默认的retrofit请求解析

最简单的retrofit下,一个登录的接口:

interface Api {
    @POST("user/login")
    fun login(@Body body: RequestBody): Call<ResponseBody>
}

注意这个接口中login方法的返回值是 Call<ResponseBody>, 这个返回值的类型在整个请求过程中十分重要!我们接下来详细说。然后就是发送请求了,最终在回调中我们获取到了ResponseBody对象,
通过ResponseBody的string()方法就可以拿到后端返回的数据,我们直接解析成我们想要的结果即可。

val api = retrofit.create(Api::class.java)
val jsonStr = JSONObject()
    .put("name", "10086")
    .put("pwd", "10010")
    .toString()
val requestBody = RequestBody.create(MediaType.parse("application/json"), jsonStr)
val call = api.login(requestBody)
call.enqueue(object : retrofit2.Callback<ResponseBody> {
    override fun onResponse(call: retrofit2.Call<ResponseBody>, response: retrofit2.Response<ResponseBody>) {
        val responseBody = response.body()
        Log.d("", responseBody.string())
    }

    override fun onFailure(call: retrofit2.Call<ResponseBody>, t: Throwable) {

    }
})

下面来看retrofit.create(Api::class.java)方法的源码:

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 {
                args = args != null ? args : emptyArgs;
                return platform.isDefaultMethod(method)
                    ? platform.invokeDefaultMethod(method, service, proxy, args)
                    : loadServiceMethod(method).invoke(args);
              }
            });
  }

retrofit使用动态代理技术,创建了一个接口的代理对象。所以当接口中的方法被执行的时候,InvocationHandler对象的invoke方法就会被触发执行。所以关键的点在于invoke方法是如何执行并发起网络请求的。platform.isDefaultMethod是判断当前环境的sdk版本要大于24并且是接口中的默认方法(这里不展开细说),大多数情况下会返回false,所以会执行loadServiceMethod()方法。loadServiceMethod方法最终会返回一个ServiceMethod对象,并且调用这个对象的invoke方法。

  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继续找,找到后存到缓存中方便下次调用直接使用。继续跟进ServiceMethod.parseAnnotations静态方法:

abstract class ServiceMethod<T> {

  static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    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);
  }


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

ServiceMethod 是一个含有 invoke 抽象方法的抽象类。parseAnnotations是一个静态方法。首先通过RequestFactory.parseAnnotations方法对Method对象解析返回了一个RequestFactory。这一步的作用就是运行时解析接口中方法的所有注解信息并将这些信息保存在RequestFactory对象中,用来构建Okhttp的request。解析注解信息这一块没什么难理解的就不再赘述。

注解信息解析之后,会把注解信息作为参数传给HttpServiceMethod.parseAnnotations方法继续解析。HttpServiceMethod是ServiceMethod的子类。这里又调用了他的静态方法parseAnnotations

static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    
    ···
    
    Annotation[] annotations = method.getAnnotations();
    Type adapterType = method.getGenericReturnType();
    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
    Type responseType = callAdapter.responseType();
    if (responseType == okhttp3.Response.class) {
      throw methodError(
          method,
          "'"
              + getRawType(responseType).getName()
              + "' is not a valid response body type. Did you mean ResponseBody?");
    }
    if (responseType == Response.class) {
      throw methodError(method, "Response must include generic type (e.g., Response<String>)");
    }

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

    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
  }

我省略了一些不太重要的代码。首先调用method.getGenericReturnType()获取了接口中方法的返回值类型,并把这个当做参数传入createCallAdapter方法中,最终返回了一个CallAdapter<ResponseT, ReturnT>对象。先看createCallAdapter:

  private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
      Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {
    return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
  }

createCallAdapter直接调用了retrofit.callAdapter方法,继续跟进:

  public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
  }
  
  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++) {
      CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }

		···
		
    throw new IllegalArgumentException(builder.toString());
  }

最终调用了nextCallAdapter方法来查找合适的CallAdapter对象,逻辑就是遍历retrofit的callAdapterFactories列表并逐个调用get方法尝试获取CallAdapter,如果找到不为null就直接返回,如果没找到最终会抛出异常。还记的这个callAdapterFactories列表吗?这个属性在retrofit构建的时候就默认初始化了,列表内添加了一个默认的实现:DefaultCallAdapterFactory。先来看这个类的get方法:

public @Nullable CallAdapter<?, ?> get(
      Type returnType, Annotation[] annotations, Retrofit retrofit) {
    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);

    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);
      }
    };
  }

方法参数中的 returnType 就是 Api 接口中定义的请求方法的返回值类型。我们的Api接口中login方法的返回值类型就是Call<ResponseBody>类型。回到上边这个方法,getRawType方法是获取一个Type的原始类型,例如我们的Call<ResponseBody>类型通过getRawType方法就会返回Call类型,通过Utils.getParameterUpperBound方法则会返回ResponseBody类型。

第一个if判断要求Api接口中方法的返回值必须是Call类型,否则返回null。第二个if判断要求Api接口中方法的返回值必须是带有泛型参数的,否则抛出异常。这两个if表达式共同决定了DefaultCallAdapterFactory只能处理Api接口中返回值是Call<T>类型的方法(请仔细想一下这句话)。所以我们在Api接口中定义的login方法的返回值是Call<ResponseBody>类型,则表明login方法最终会被DefaultCallAdapterFactory处理。最终创建并返回了一个CallAdapter的匿名类。这个匿名类的responseType方法最终返回的responseType类型就是login方法中的ResponseBody,adapt方法中由于executor不为null(其实就是retrofit构建时的那个主线程的线程池),返回了一个ExecutorCallbackCall对象。ExecutorCallbackCall其实就是一层包装,它内部持有主线程的线程池和原始的Call对象。

static final class ExecutorCallbackCall<T> implements Call<T> {
    final Executor callbackExecutor;
    final Call<T> delegate;

    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }

    @Override
    public void enqueue(final Callback<T> callback) {
      Objects.requireNonNull(callback, "callback == null");

      delegate.enqueue(
          new Callback<T>() {
            @Override
            public void onResponse(Call<T> call, final Response<T> response) {
              callbackExecutor.execute(
                  () -> {
                    if (delegate.isCanceled()) {
                      // Emulate OkHttp's behavior of throwing/delivering an IOException on
                      // cancellation.
                      callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
                    } else {
                      callback.onResponse(ExecutorCallbackCall.this, response);
                    }
                  });
            }

            @Override
            public void onFailure(Call<T> call, final Throwable t) {
              callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
            }
          });
    }
    
    ···
}

所以我们定义的login方法最终返回的Call类型的实例对象就是这个ExecutorCallbackCall。他会在最终的onResponse方法中使用线程池切换到主线程,并在主线程中回调我们的callback。

到这里我们在往回看,DefaultCallAdapterFactory可以处理我们login方法的返回值类型,所以他的get方法返回了一个匿名的CallAdapter对象。retrofit类的nextCallAdapter在遍历的过程中找到了CallAdapter对象并返回,最终回到了HttpServiceMethod的静态方法parseAnnotations中(这一口气太tmd长了)。现在再重新回顾一下parseAnnotations方法:

static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    
    ···
    
    Annotation[] annotations = method.getAnnotations();
    Type adapterType = method.getGenericReturnType();
    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
    Type responseType = callAdapter.responseType();
    if (responseType == okhttp3.Response.class) {
      throw methodError(
          method,
          "'"
              + getRawType(responseType).getName()
              + "' is not a valid response body type. Did you mean ResponseBody?");
    }
    if (responseType == Response.class) {
      throw methodError(method, "Response must include generic type (e.g., Response<String>)");
    }

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

    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
  }

在找到了callAdapter对象后调用它的callAdapter.responseType()方法拿到一个类型responseType,这里就是login方法中返回值的泛型类型:ResponseBody。下面有两个判断,如果我们login方法中返回值的泛型类型是 okhttp3.Response 或者 retrofit.Response就直接抛出异常。说明我们login方法的返回值Call<T>中的泛型不是乱写的。那是不是泛型必须是ResponseBody?直接写一个我们自定义的User实体类可以吗?这就又涉及到我们请求回来之后想把响应数据转化成什么类型(这块很重要!),如果我们给retrofit设置了GsonConverterFactory,那么login方法的返回值就可以直接写成Call<User>类型因为GsonConverterFactory自动为我们做了数据转换,如果没设置任何数据转化的工厂,默认情况下则必须是ResponseBody!!

接着向下看就是根据responseType的类型去查找相应的responseConverter了,okhttp发送请求后最终会在回调中得到okhttp3.Response对象,okhttp3.Response的body()方法会得到ResponseBody对象,responseConverter的作用就是将ResponseBody转化为我们想要的类型。先看createResponseConverter方法:

  private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter(
      Retrofit retrofit, Method method, Type responseType) {
    Annotation[] annotations = method.getAnnotations();
    return retrofit.responseBodyConverter(responseType, annotations);
  }

直接调用了retrofit.responseBodyConverter方法,继续跟进:

public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
    return nextResponseBodyConverter(null, type, annotations);
  }


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) {
        //noinspection unchecked
        return (Converter<ResponseBody, T>) converter;
      }
    }
    
    ···
    
    throw new IllegalArgumentException(builder.toString());
  }

可以看到Converter的查找方式和上面说的CallAdapter是一样的,遍历列表并逐个调用responseBodyConverter()方法尝试获取converter。还记得converterFactories列表吗?在第一节retrofit构建的时候converterFactories列表也被初始化了并且添加了一个默认的实现:BuiltInConverters,直接看这个类:

final class BuiltInConverters extends Converter.Factory {
 
  @Override
  public @Nullable Converter<ResponseBody, ?> responseBodyConverter(
      Type type, Annotation[] annotations, Retrofit retrofit) {
    if (type == ResponseBody.class) {
      return Utils.isAnnotationPresent(annotations, Streaming.class)
          ? StreamingResponseBodyConverter.INSTANCE
          : BufferingResponseBodyConverter.INSTANCE;
    }
    
    ...
    
    return null;
  }
}

BuiltInConverters是Converter.Factory的默认实现,responseBodyConverter方法中只有当type是ResponseBody.class的时候才会返回对象否则返回null,也就是说BuiltInConverters只处理Api接口中方法的返回值是泛型参数为ResponseBody类型的数据(请思考三秒钟)。我们在Api接口中定义的login方法的返回值为Call<ResponseBody>,所以BuiltInConverters可以处理login方法最终的请求响应数据转化。到这里就已经说明了一个问题,在retrofit默认构建的情况下接口中定义的方法的返回值必须是Call<ResponseBody>类型!!! 否则就会因为找不到相应的CallAdapter和Converter而抛出异常。

由于我们的请求是普通的接口请求不是下载流,所以Utils.isAnnotationPresent(annotations, Streaming.class)会返回false。所以最终会返回BufferingResponseBodyConverter.INSTANCE对象。

  static final class BufferingResponseBodyConverter implements Converter<ResponseBody, ResponseBody>{
    static final BufferingResponseBodyConverter INSTANCE = new BufferingResponseBodyConverter();

    @Override
    public ResponseBody convert(ResponseBody value) throws IOException {
      try {
        // Buffer the entire body to avoid future I/O.
        return Utils.buffer(value);
      } finally {
        value.close();
      }
    }
  }

BufferingResponseBodyConverter只是把ResponseBody做了一下处理就直接返回了,他并没有做任何的数据转化。换句话说BufferingResponseBodyConverter就是将okhttp请求的响应ResponseBody做了缓存就直接返回了,数据转化的工作需要我们自己处理。所以回到文章开头我们用retrofit发起登陆的请求,login方法最终的返回值是Call<ResponseBody>,并且在最终的onResponse方法中我们获取到的响应也是Response<ResponseBody>。

是时候总结一下了,在retrofit默认构建的情况下,我们Api接口中方法的返回值必须是Call<ResponseBody>,其中retrofit提供了DefaultCallAdapterFactory来处理返回值类型为Call<T>类型的线程切换,BuiltInConverters来处理 ResponseBody -> ResponseBody 的数据转化。

到这里我们再继续往回看,BuiltInConverters可以处理 ResponseBody -> ResponseBody 的数据转化所以返回BufferingResponseBodyConverter.INSTANCE对象,retrofit的nextResponseBodyConverter在遍历中找到了相应的Converter并返回,最终又回到了HttpServiceMethod的静态方法parseAnnotations中。现在再重新回顾一下parseAnnotations方法:

static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    
    ···
    
    Annotation[] annotations = method.getAnnotations();
    Type adapterType = method.getGenericReturnType();
    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
    Type responseType = callAdapter.responseType();
    if (responseType == okhttp3.Response.class) {
      throw methodError(
          method,
          "'"
              + getRawType(responseType).getName()
              + "' is not a valid response body type. Did you mean ResponseBody?");
    }
    if (responseType == Response.class) {
      throw methodError(method, "Response must include generic type (e.g., Response<String>)");
    }

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

    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
  }

到现在为止,CallAdapter和Converter我们都找到了,并且最终返回了一个CallAdapted对象。看一下源码:

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

CallAdapted原来是HttpServiceMethod的子类,所以CallAdapted也就是最终找到的ServiceMethod。到现在我们只是完成构建了一个ServiceMethod的工作,但是真正的网络请求其实还没有发出去,在retrofit的create方法中可以看到动态代理对象最终调用了ServiceMethod.invoke(args)方法,这个方法才是真正发出网络请求的地方。

现在让我们重新捋一遍,ServiceMethod是一个抽象类并没有实现invoke()方法,HttpServiceMethod继承了ServiceMethod方法实现了invoke()方法:

abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
	
  @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);

}

OkHttpCall对象是retrofit提供的实现类,他内部封装了Okhttp发送网络请求的逻辑(真正发送okhttp请求的地方!!!)。并且在网络请求回调中使用上边找到的Converter对数据进行转化。里边的逻辑很清晰就不细说了。

CallAdapted是HttpServiceMethod的子类,并且实现了adapt()方法。在adapt方法中使用CallAdapter对OkhttpCall对象进行了一层包装,这层包装的目的就是完成了请求回调自动切换到主线程执行!

三、默认的retrofit请求总结

ok,到这里默认的retrofit发起网络请求的流程就基本分析完了。整个流程下来可以分为两条主线,一条是构建ServiceMethod,一条是调用ServiceMethod的invoke发起网络请求。两条主线中涉及到线程切换、响应数据转化两件重要的事情,分别对应于 DefaultCallAdapterFactory 和 BuiltInConverters。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值