Retrofit2源码解析

933 阅读11分钟

一、 前言

本文主要讲Retrofit原理以及我对这个库设计的理解和看法。写这篇文章的主要目的是加深自己对Retrofit的理解, 同时也希望能够给正在学习Retrofit的同学提供一些帮助。如果有哪里写的不对的地方,欢迎拍砖。 (Ps: 本文源码为retrofit2.9.0)

全文结构如下

  1. 前言
  2. Retrofit简介
  3. Retrofit的核心接口
  4. Retrofit的原理及运作流程
  5. 总结

二、 Retrofit简介

(一)、 为什么要Retrofit这个库?

这个库是为了让网络请求的构建以及网络完成后的response处理更加简便

(二)、 Retrofit是干嘛的?

很多同学会以为Retrofit是一个网络请求库。不对, 它不负责网络请求的执行。这个库的功能主要是

  • 简化网络请求的创建
  • 处理Response body(如反序列化)
  • 灵活处理Response返回类型(如返回Rx的Single)

三、 Retrofit的接口设计

先看retrofit工程的目录结构

我们需要关注的是它定义的四个核心接口, 分别是

  • Call接口
  • CallAdapter接口
  • Callback接口
  • Converter接口

(一)、 Call接口

思考两个问题

  • 这个接口是干嘛的?
  • 如果让你设计这个接口你怎么设计?
  1. 先讲讲我的想法, Call接口是用来表述一个网络请求任务的, 是一个task。 如果我设计这个接口的话, 我会提供以下方法
    //同步执行请求, 直接返回response
    fun execute(request: Request): Response
    
    //同步执行请求,回调返回response
    fun executeAsync(request: Request, callback: (response: Response)-> Unit)
    
    //取消请求
    fun cancel()
  1. 思考过后, 我们再看看他的源码
/**
 * 这是一个retrofit的方法调用, 能够发送请求并且返回响应。
 *
 * @param <T> 响应成功的response body 类型
 */
public interface Call<T> extends Cloneable {
  /**
   * 同步发送请求
   */
  Response<T> execute() throws IOException;

  /**
   * 异步发送请求
   */
  void enqueue(Callback<T> callback);

  /**
   * 请求是否已经执行过execute或者enqueue
   */
  boolean isExecuted();

  /**
   * 取消请求
   */
  void cancel();

  /** True if {@link #cancel()} was called. */
  boolean isCanceled();

  /** 拷贝 */
  Call<T> clone();

  /** 返回请求request */
  Request request();

  /**
   * Returns a timeout that spans the entire call: resolving DNS, connecting, writing the request
   * body, server processing, and reading the response body. If the call requires redirects or
   * retries all must complete within one timeout period.
   */
  Timeout timeout();
}

可以看到, 和我的想法基本一致。 不过这里有个很奇怪的点, 大家看request方法, 这个方法的返回值Request是okhttp库里的Request,这说明retrofit库直接引用了okhttp库。

个人觉得这个可以算Retrofit的设计缺陷。如果是我设计的话, 我肯定会在自己库里自己定义request数据结构,再提供一个转换接口暴露给app层。假设我只想用retrofit库而不想用okhttp库, 那么retrofit目前的设计就失去了这种灵活性。 不知道大家有什么看法。

(二)、 CallAdapter接口

同样, 思考两个问题

  • 这个接口是干嘛的?
  • 如果让你设计这个接口你怎么设计?
  1. 这个接口是用来把Response<T>转成我们需要的类型, 比如Single<T>或者其他。 如果我设计这个接口的话, 我会提供以下方法
    fun adapterCall(call: Call<T>): R<T>
  1. 现在我们看他源码
/**
 * Adapts a {@link Call} with response type {@code R} into the type of {@code T}. Instances are
 * created by {@linkplain Factory a factory} which is {@linkplain
 * Retrofit.Builder#addCallAdapterFactory(Factory) installed} into the {@link Retrofit} instance.
 */
public interface CallAdapter<R, T> {
  /**
   * 最终客户端需要的返回responsebody数据类型
   * 如:
   * @GET("v1/test")
   * fun test(): Single<User>
   * 这个接口, 那么此时的responseType返回的就是User
   */
  Type responseType();

  /**
   * 大概就是把retrofit的Call<T>转成一个新的Call<T>(比如okhttp的Call),看了注释里面的sample应该都能看的明白
   * Returns an instance of {@code T} which delegates to {@code call}.
   *
   * <p>For example, given an instance for a hypothetical utility, {@code Async}, this instance
   * would return a new {@code Async<R>} which invoked {@code call} when run.
   *
   * <pre><code>
   * @Override
   * public <R> Async<R> adapt(final Call<R> call) {
   *   return Async.create(new Callable<Response<R>>() {
   *     @Override
   *     public Response<R> call() throws Exception {
   *       return call.execute();
   *     }
   *   });
   * }
   * </code></pre>
   */
  T adapt(Call<R> call);

  /**
   * CallAdapter创建工厂
   */
  abstract class Factory {
    /**
     * 比如接口声明的方法是
     * @GET("v1/test")
     * fun test(): Single<User>
     * 那么这个方法就会返回CallAdapter<User, Single<User>>
     */
    public abstract @Nullable CallAdapter<?, ?> get(
        Type returnType, Annotation[] annotations, Retrofit retrofit);

    /**
     * 获取泛型参数, Single<User>, 返回User
     */
    protected static Type getParameterUpperBound(int index, ParameterizedType type) {
      return Utils.getParameterUpperBound(index, type);
    }

    /**
     * 获取泛型前面的那个类型, 如Single<User>, 返回Single
     */
    protected static Class<?> getRawType(Type type) {
      return Utils.getRawType(type);
    }
  }
}

(三)、 Callback接口

这个接口很简单, 就是一个请求回调的接口, 不细说了, 直接贴代码


/**
 * Communicates responses from a server or offline requests. One and only one method will be invoked
 * in response to a given request.
 *
 * <p>Callback methods are executed using the {@link Retrofit} callback executor. When none is
 * specified, the following defaults are used:
 *
 * <ul>
 *   <li>Android: Callbacks are executed on the application's main (UI) thread.
 *   <li>JVM: Callbacks are executed on the background thread which performed the request.
 * </ul>
 *
 * @param <T> Successful response body type.
 */
public interface Callback<T> {
  /**
   * Invoked for a received HTTP response.
   *
   * <p>Note: An HTTP response may still indicate an application-level failure such as a 404 or 500.
   * Call {@link Response#isSuccessful()} to determine if the response indicates success.
   */
  void onResponse(Call<T> call, Response<T> response);

  /**
   * Invoked when a network exception occurred talking to the server or when an unexpected exception
   * occurred creating the request or processing the response.
   */
  void onFailure(Call<T> call, Throwable t);
}

唯一需要注意的地方是, 如果没有特别声明, 此回调会在主线程执行(至于为什么, 下面的流程分析会讲到)

(四)、 Converter接口

老规矩, 思考两个问题

  • 这个接口是干嘛的?
  • 如果让你设计这个接口你怎么设计?

这个接口是用来做类型转换的。我先说说我的想法, 因为retrofit构建好的Request是retrofit自己定义的request, 直接传给网络请求库他不认识, 所以需要一个把retrofit的request转成网络请求库认识的requestBody。同时, 网络请求库返回的response也需要转成客户端需要的数据类型。 所以这个接口如果让我设计, 它大概长这样

    //retrofit的request转成实际网络请求执行时候需要的Request, 如retrofit的request转成Okhttp的Request
    fun convertRequest(request: Request): T
    
    //把网络请求执行返回的ResponseBody转成客户端需要的数据类型,如Okhttp的ResponseBody转成客户端定义的User
    fun convertResponse(responseBody: R): S

好,现在看它源码


/**
 * Convert objects to and from their representation in HTTP. Instances are created by {@linkplain
 * Factory a factory} which is {@linkplain Retrofit.Builder#addConverterFactory(Factory) installed}
 * into the {@link Retrofit} instance.
 */
public interface Converter<F, T> {

  /** 很简单, 就是把输入的F转成输出的T。 */
  @Nullable
  T convert(F value) throws IOException;

  /** 创建工厂 */
  abstract class Factory {
    /**
     * 返回一个convert对象,
     * 这个convert可以把输出ResponseBody转成Type。这个Type是由CallAdapter的responseType()方法
     * 的返回值决定的。
     */
    public @Nullable Converter<ResponseBody, ?> responseBodyConverter(
        Type type, Annotation[] annotations, Retrofit retrofit) {
      return null;
    }

    /**
     * 返回一个convert对象, 这个convert可以把输入Type转成RequestBody。 
     * 这个的Type通常是从@Body@Part或者@PartMap得到。
     */
    public @Nullable Converter<?, RequestBody> requestBodyConverter(
        Type type,
        Annotation[] parameterAnnotations,
        Annotation[] methodAnnotations,
        Retrofit retrofit) {
      return null;
    }

    /**
     * 返回一个convert对象, 这个convert可以把输入Type转成String。 
     * 这个的Type通常是从@Field@FieldMap@Header@HeaderMap@Path@Query或者@QueryMap
     * 得到。
     */
    public @Nullable Converter<?, String> stringConverter(
        Type type, Annotation[] annotations, Retrofit retrofit) {
      return null;
    }

    /**
     * 获取泛型参数, Single<User>, 返回User
     */
    protected static Type getParameterUpperBound(int index, ParameterizedType type) {
      return Utils.getParameterUpperBound(index, type);
    }

    /**
     * 获取泛型前面的那个类型, 如Single<User>, 返回Single
     */
    protected static Class<?> getRawType(Type type) {
      return Utils.getRawType(type);
    }
  }
}

可以看到和我设想的样子相差甚远。retrofit设计的Converter接口职责拆的更细更单一, 构建起来更优雅。不过这个接口同样有我上文提到的强依赖okhttp库的问题。

四、 Retrofit的原理及流程

通常开发中retrofit会和okhttp、RxJava一起使用, 所以我先按照这三个库一起使用写一个简单的例子。

示例代码


interface SampleApi {
    @POST("sample/wakaka")
    fun updateUserInfo(@Body param: @JvmSuppressWildcards Map<String, Any>): Single<BaseBean<User>>
}

val okHttpClient : OkHttpClient // okhttp相关细节不在本文讲述

//第一步
val retrofit = Retrofit.Builder()
        .baseUrl("https://api.github.com/")
        .callFactory(okHttpClient)
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
        .build()

//第二步
val sampleApi = retrofit.create(SampleApi::class.java)

//第三步
val singleTask = sampleApi.updateUserInfo(paramsMap)

下面的流程分析都会根据这个示例代码进行分析

第一步, 构建retrofit

Builder模式构建retrofit, 基本都是一些赋值的操作。 唯一需要注意的地方是Retrofit.Builder()这个方法

    public final class Retrofit {
      ...
      public static final class Builder {
        ...
        public Builder() {
          this(Platform.get()); //Platform.get()会在安卓中会返回Android这个对象
        }
      }
    }

我们看看Android这个对象

static class Android extends Platform {
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
      if (callbackExecutor == null) throw new AssertionError();
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }

    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override public void execute(Runnable r) {
        handler.post(r);
      }
    }
  }

所以retrofit如果没有手动配置过callbackExecutor的话, 默认Callback会在主线程执行。 ( Handler和Looper相关的内容也不在这篇文章赘述了, 做安卓应该都知道 )

第二步, 动态代理实现网络接口的实现

如示例代码中的SampleApi, 他是一个接口, 如果想要他是可执行的类, 我们通常的做法是声明一个类继承它, 然后在里面处理它的具体实现。我们来看看retrofit他是怎么设计

 public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
        
          //就是上文讲过的Android
          private final Platform platform = Platform.get();

          @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {
              
            //如果是Object自己的方法, 就直接调用了, 如toString(), hashCode()等等
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            
            //Android的isDefaultMethod方法恒返回false, 所以这个方法不用看了
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            
            //step1
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
                
            
            //step2
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.adapt(okHttpCall);
          }
        });
  }

哦, retrofit用的是动态代理来实现接口的调用。(动态代理的相关知识不在本文讲述)我们重点来看它的invoke方法。

step1

loadServiceMethod方法, 把method解析成ServiceMethod对象

public final class Retrofit {
  private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
 
  ServiceMethod<?, ?> loadServiceMethod(Method method) {
    //先从缓存中直接拿ServiceMethod
    ServiceMethod<?, ?> result = serviceMethodCache.get(method);
    
    //若缓存中有, 则直接返回
    if (result != null) return result;

    //虽然用的ConcurrentHashMap, 但是复合操作还是不能保证原子性, 所以这里用synchronized上锁
    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        //若缓存没有, 则创建一个ServiceMethod, 并把它加入缓存
        result = new ServiceMethod.Builder<>(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  } 
}

按照示例代码走, new ServiceMethod.Builder<>(this, method).build()这个build方法会创建出 RxJava2CallAdapter<Object, Object>, GsonResponseBodyConverter<BaseBean<User>>, GsonRequestBodyConverter<Map>, 最后创建出ServiceMethod对象。

此处我有一个优化想法, loadServiceMethod方法是中通过key从缓存取value, 若value不存在则新建对象并添加到缓存中。 retrofit用的是synchronize悲观锁锁住了这一段代码, 那么此处是否可以优化改用乐观锁呢?看到这种需求我首先想到的是ConcurrentHashMap的putIfAbsent方法。 但是putIfAbsent这个方法需要直接传value, 而我们的value构建是耗时的。 我们的需求是先判断不存在, 再创建实例,再put, 并且要保证这三个步骤的原子性。 我的想法是, 改造一下ConcurrentHashMap, 新加一个putIfAbsentByLazyInit方法,不过最后我却发现这个思路似乎不可行, 因为最终compareAndSwapObject还是需要传入具体的value, 因此我的想法是错误的。。。不知道大家有没有什么想法, 欢迎分享。

class MyConcurrentHashMap<K, V> : ConcurrentHashMap<K,V>{
    
    fun putIfAbsentByLazyInit(K key, factory: DataFactory<V>) {
        ...
    }
    
    interface DataFactory<V> {
        fun get(): V
    }
}

step2

构建OkHttpCall, 然后调用RxJava2CallAdapter的adapter方法, 输入的参数是OkHttpCall

final class RxJava2CallAdapter<R> implements CallAdapter<R, Object> {
    @Override public Object adapt(Call<R> call) {
    
    //RxJava2CallAdapterFactory.create()构建的, isAsync为false
    Observable<Response<R>> responseObservable = isAsync
        ? new CallEnqueueObservable<>(call)
        : new CallExecuteObservable<>(call);

    Observable<?> observable;
    if (isResult) {
        observable = new ResultObservable<>(responseObservable);
    } else if (isBody) {    //此示例中isBody为true
        observable = new BodyObservable<>(responseObservable);
    } else {
        observable = responseObservable;
    }

    if (scheduler != null) {
        observable = observable.subscribeOn(scheduler);
    }

    if (isFlowable) {
        return observable.toFlowable(BackpressureStrategy.LATEST);
    }
    if (isSingle) { //此示例中isSingle为true
        return observable.singleOrError();
    }
    if (isMaybe) {
        return observable.singleElement();
    }
    if (isCompletable) {
        return observable.ignoreElements();
    }
    return observable;
    }
}

大概流程 先创建CallExecuteObservable, 在创建BodyObservableCallExecuteObservable包了一层, 有点代理的意思, 但不完全正确, 最后在根据接口定义好的Rx流转成与之匹配的Rx流, 本示例中是Single。 下面看看这两个Observable是怎么实现的吧。

final class CallExecuteObservable<T> extends Observable<Response<T>> {
  private final Call<T> originalCall;

  CallExecuteObservable(Call<T> originalCall) {
    this.originalCall = originalCall;
  }

  @Override protected void subscribeActual(Observer<? super Response<T>> observer) {
    // Since Call is a one-shot type, clone it for each new observer.
    Call<T> call = originalCall.clone();
    
    //负责控制任务发射
    CallDisposable disposable = new CallDisposable(call);
    observer.onSubscribe(disposable);

    boolean terminated = false;
    try {
      Response<T> response = call.execute();
      if (!disposable.isDisposed()) {
        observer.onNext(response);
      }
      if (!disposable.isDisposed()) {
        terminated = true;
        observer.onComplete();
      }
    } catch (Throwable t) {
      Exceptions.throwIfFatal(t);
      if (terminated) {
        RxJavaPlugins.onError(t);
      } else if (!disposable.isDisposed()) {
        try {
          observer.onError(t);
        } catch (Throwable inner) {
          Exceptions.throwIfFatal(inner);
          RxJavaPlugins.onError(new CompositeException(t, inner));
        }
      }
    }
    
    //怎么感觉这东东有点像阉割版的Emitter啊,可能是Rx1的时候的代码吧, 哈哈。
    private static final class CallDisposable implements Disposable {
        private final Call<?> call;
        private volatile boolean disposed;
    
        CallDisposable(Call<?> call) {
          this.call = call;
        }
    
        @Override public void dispose() {
          disposed = true;
          call.cancel();
        }
    
        @Override public boolean isDisposed() {
          return disposed;
        }
      }
  }
}

这个类就是在ObservablesubscribeActual时候, 执行call.execute(), 再把它发到Observer。按照示例代码, 就是把Call<BaseBean>转成Single<Response<BaseBean>>。 BodyObservable这个类代码就不贴了, 很简单, 就是把Single<Response<BaseBean>>转成Single<BaseBean>。

总结

这张图完美的诠释了Retrofit的整个流程图

Ps: 图片来自网络