Retrofit源码分析

245 阅读5分钟

什么是Retrofit

  • retrofit 是Square公司为了方便网络请求,对自己okhttp底层网络请求进行了再一次封装的框架,意在简化网络请求调用。当然retrofit设计也并不单纯只为了okhttp服务,只是默认实现使用了okhttp。

Retrofit的实现

先来看retrofit的几个重要类

Retrofit

Retrofit adapts a Java interface to HTTP calls by using annotations on the declared methods to define how requests are made. Create instances using {@linkplain Builder the builder} and pass your interface to {@link #create} to generate an implementation.

  • 通过动态代理的方式,解析方法申明上的注解来生成http请求。
  • Retrofit实例主要充当一个适配器的角色。
Call

An invocation of a Retrofit method that sends a request to a webserver and returns a response. Each call yields its own HTTP request and response pair. Use {@link #clone} to make multiple calls with the same parameters to the same webserver; this may be used to implement polling or to retry a failed call.

  • Retrofit方法的一个实现,向服务器发送一个请求,并返回一个响应
  • 保存了一对http的请求以及响应
Converter<F, T>

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.

  • 对http响应进行转换,转换成请求接口需要的返回类型
CallAdapter<R, T>

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.

  • 对请求进行适配,以满足接口要求
ServiceMethod<R, T>

Adapts an invocation of an interface method into an HTTP call.

  • 将定义的网络请求方法适配成一个http call
ParameterHandler
  • ServiceMethod解析参数时具体值保存的位置
RequestBuilder
  • 构建一个初始的Request

Retrofit发起请求的过程

  • 先看一下调用的代码。

    Retrofit创建时使用的动态代理方式,中间的Platform就是根据不同的平台做了兼容。这里可以很清晰看到,对service进行代理,通过其中的method构建一个serviceMethod,进而new出okHttpCall,并使用serviceMethod内部持有的callAdapter对okHttpCall进行网路请求以及适配成用户期望的返回类型,完成一次网络请求。

    
    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() {
          private final Platform platform = Platform.get();
    
          @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {
            // If the method is a method from Object then defer to normal invocation.
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
    }
    
    
  • ServiceMethod的构建

    ServiceMethodg构建过程主要是对Service中定义的网络请求进行注解的解析处理,将完成的参数保存在ParameterHandler中以便后续取用,至于注解参数的获取比较琐碎,这里不做赘述。

  • CallAdapter的获取

    private CallAdapter<T, R> createCallAdapter() {
      Type returnType = method.getGenericReturnType();
      if (Utils.hasUnresolvableType(returnType)) {
        throw methodError(
            "Method return type must not include a type variable or wildcard: %s", returnType);
      }
      if (returnType == void.class) {
        throw methodError("Service methods cannot return void.");
      }
      Annotation[] annotations = method.getAnnotations();
      try {
        //noinspection unchecked
        return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
      } catch (RuntimeException e) { // Wide exception range because factories are user code.
        throw methodError(e, "Unable to create call adapter for %s", returnType);
      }
    }
    
    

    这里开始用到了工厂模式,使用CallAdapter.Factory的方式来获取CallAdapter。我们知道在构建Retrofit时是可以addCallAdapterFactory的,这就意味着我们可以自己实现CallAdapter,提供给Retrofit使用,提高代码的扩展性。

    通过遍历Retrofit中保存的CallAdapter.Factory列表获取到符合条件的Factory用做请求的转换。

    通过上面代码可以知道,实际上获取到的时候是retrofit中默认初始化的CallAdapter

  • 默认CallAdapter

    在Retrofit build过程中可以看到如下代码

    
     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> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
      
    

    通过平台的适配我们获取到的platform其实是如下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);
      }
    }
    }
    

    通过安卓平台可以初始化一个默认的ExecutorCallAdapterFactory,用以获取默认的CallAdapter。

    通过ExecutorCallAdapterFactory可以get到一个CallAdapter的实现,并将Call适配成一个ExecutorCallbackCall,内部处理了网络请求以及线程的切换。

  • 请求的梳理

    通过上面的分析知道,默认的请求过程如下:

    1. 对Service进行动态代理
    2. 构建出ServiceMethod
    3. 通过ServiceMethod构建出OkHttpCall
    4. 通过ServiceMethod中的CallAdapter实际也就是ExecutorCallAdapterFactory,对OkHttpCall进行适配获取到我们所需要的Call对象
    5. 得到用户需要的Call之后就可以进行execute或者enqueue操作。

    到这里基本的网络请求算是完了。

·~~~~~~~~~~~~~~~~~~·

·~~~~~~~~~~~~~~~~~~·

·~~~~~~我是分割线~~~~~~~·

·~~~~~~~~~~~~~~~~~~·

·~~~~~~~~~~~~~~~~~~·

等等!是不是感觉漏掉了什么东西,前面提到的Converter好像用到。

开头说过Converter是对响应做了转换,那肯定是在Call中用到,那我们回过头去看OkHttpCall的构建。

  • OkHttpCall

    主要看一下response的解析

    
    Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    ResponseBody rawBody = rawResponse.body();
    
    // Remove the body's source (the only stateful object) so we can pass the response along.
    rawResponse = rawResponse.newBuilder()
        .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
        .build();
    
    int code = rawResponse.code();
    if (code < 200 || code >= 300) {
      try {
        // Buffer the entire body to avoid future I/O.
        ResponseBody bufferedBody = Utils.buffer(rawBody);
        return Response.error(bufferedBody, rawResponse);
      } finally {
        rawBody.close();
      }
    }
    
    if (code == 204 || code == 205) {
      rawBody.close();
      return Response.success(null, rawResponse);
    }
    
    ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
    try {
      T body = serviceMethod.toResponse(catchingBody);
      return Response.success(body, rawResponse);
    } catch (RuntimeException e) {
      // If the underlying source threw an exception, propagate that rather than indicating it was
      // a runtime exception.
      catchingBody.throwIfCaught();
      throw e;
    }
    }
    
    

    我们来看这一句

    T body = serviceMethod.toResponse(catchingBody);
    

    往上追溯到头可以知道,实际代码如下

    public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
      @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
    checkNotNull(type, "type == null");
    checkNotNull(annotations, "annotations == null");
    
    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;
      }
    }
    
    

    也就是我们常设置的GsonConverterFactory会在这里被取用,并对真正的response做解析。

    至此一个完整的网络请求以及参数的解析都完整结束了

总结

  1. Retrofit本身就是个适配器,用以协调资源
  2. 动态代码模式,每个请求都是动态生成
  3. 静态代理模式,如返回给我们的ExecutorCallbackCall,实际是对内部Call一个代理对象
  4. builder模式,简化对象的构建
  5. 使用了工厂模式,同时提高了代码的定制性
  6. 适配器模式,将原始的响应适配成实际需要的类型