Retrofit源码分析

在学习了Retrofit分析-漂亮的解耦套路(视频版)后,自己又仔细的钻研了一下Retrofit的源码,也大致清楚了Retrofit进行网络请求的步骤。好记性不如烂笔头,以文章的形式将对于Retrofit的思考记录下来,也加深理解。(如有错误,请不吝赐教)

分析源码的一般姿势

首先我们聊一下对于一个优秀的libary,应该怎样一步一步地分析它。在上面的视频中,介绍了一个很好的方法。分为三个阶段:

  • what: 这个框架是用来干什么的,暴露给用户的API都是用来干嘛的。
  • how: 这个API内部是怎样实现的,整个框架正常调用时内部是一个怎样的流程。
  • why: 为什么要这样实现,有什么好处,可不可以有其他的实现,与原来的实现相比怎么样。

通过了解、深入、思考,将整个框架一层一层地剖析出来,由浅入深,最后从全局再看这个框架,或许我们会不自禁的赞叹代码的美妙。

Retrofit使用(what)

详细的了解Retrofit使用及API可以到Retrofit的Github

简单使用

首先,我们需要创建一个请求接口,内部是一个请求方法,通过注解的方式定义请求类型及url

public interface IHttpRequestTest {
    @GET("api/data/福利/{number}/{page}")
    Call<BaseModel<ArrayList<Benefit>>> getBenefits(@Path("number") int number, @Path("page") int page);
}

然后我们就可以愉快地使用Retrofit。

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://gank.io/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();
IHttpRequestTest iHttpRequestTest = retrofit.create(IHttpRequestTest.class);
Call<BaseModel<ArrayList<Benefit>>> call = iHttpRequestTest.getBenefits(40, 2);
call.enqueue(new Callback<BaseModel<ArrayList<Benefit>>>() {
    @Override
    public void onResponse(@NonNull Call<BaseModel<ArrayList<Benefit>>> call, @NonNull Response<BaseModel<ArrayList<Benefit>>> response) {
        if(response.body() != null && response.body().results != null){
            myAdapter.setData(response.body().results);
        }
    }

    @Override
    public void onFailure(@NonNull Call<BaseModel<ArrayList<Benefit>>> call, Throwable t) {
        Toast.makeText(MainActivity.this, "请求失败:" + t.getMessage(),Toast.LENGTH_SHORT).show();
    }
});

一般http的请求步骤

http请求步骤
如上图,对于一般http请求:

  • 生成request请求,包括请求类型,url等等,放入Excutor队列
  • 请求在Excutor中循环进行httpcall请求
  • 等待请求回调

接下来,我们就可以根据这个一般的http请求步骤,通过debug的形式弄清楚Retrofit的内部逻辑。

Retrofit源码解析

探索Retrofit对象初始化时参数的真正含义

首先第一步,就是生产Retrofit对象,并传入基本的参数。

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://gank.io/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();

进入Retrofit类的源码,可以看到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();
    }
    //如果callbackExcutor为空,创建默认的callbackEcxutor
    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
    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,将使用默认的converterFactories
    converterFactories.addAll(platform.defaultConverterFactories());
    //返回Retrofit对象,包括在Builder中添加的自定义参数。
    return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
        unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}

可以看到,生成的retrofit对象有五个参数必须要存在。

  • baseUrl就不用多说了,是必须的。
  • callFactory使用的是OkHttp3中的OkHttpClient
  • callbackExcutorcallAdapterFactory中的callAdapter都对应一般请求步骤中的Excutor,只不过callbackExcutor用于在请求内部回调中切换线程,回调的方法存在哪个线程中取决于callbackExcutor在哪个线程。比如请求要在子线程中,回调的方法在主线程中。
  • callAdapter是真正的请求对象,callbackExcutor相当于在callAdapter中切换线程。
  • converterFactory是用来解析返回的json数据的。当然这些具体的解释在下面的分析中都会看到。

有源码可看出,默认的callbackExcutorcallAdapterFactoryconverterFactory添加都与platform对象有关。这是一个Platform类,进入研究一下。

class Platform {
  private static final Platform PLATFORM = findPlatform();
  static Platform get() {
    return PLATFORM;
  }

  private static Platform findPlatform() {
    try {
      Class.forName("android.os.Build");
      if (Build.VERSION.SDK_INT != 0) {
        return new Android();
      }
    } catch (ClassNotFoundException ignored) {
    }
    try {
      Class.forName("java.util.Optional");
      return new Java8();
    } catch (ClassNotFoundException ignored) {
    }
    return new Platform();
  }

  @Nullable Executor defaultCallbackExecutor() {return null;}

  List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
      @Nullable Executor callbackExecutor) {...}

  List<? extends Converter.Factory> defaultConverterFactories() {...}

  @IgnoreJRERequirement // Only classloaded and used on Java 8.
  static class Java8 extends Platform {...}

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

    @Override List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
        @Nullable Executor callbackExecutor) {
      if (callbackExecutor == null) throw new AssertionError();
      ExecutorCallAdapterFactory executorFactory = new ExecutorCallAdapterFactory(callbackExecutor);
      return Build.VERSION.SDK_INT >= 24
        ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
        : singletonList(executorFactory);
    }

    @Override List<? extends Converter.Factory> defaultConverterFactories() {
      return Build.VERSION.SDK_INT >= 24
          ? singletonList(OptionalConverterFactory.INSTANCE)
          : Collections.<Converter.Factory>emptyList();
    }

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

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

内容有点多,这里我只提取了对现在有用的。整体来看,Platform内部有两个子类继承了该类Android与Java8。还有一个get方法,获取Platform静态实例,静态实例调用findPlatform()方法。这个方法是根据程序所执行的环境决定是返回一个Android实例还是Java8实例或者Platform实例。这里我们的环境是Android,所以具体看Android类中的方法。

  • defaultCallbackExecutor()方法,返回了MainThreadExecutor类实例。此类在Android类内部,可以清晰的看出其中的handler静态变量是用的主线程的looper。也就是说,默认的callbackExcutor是运行在主线程的。
  • defaultCallAdapterFactories()方法,参数是上面得到的callbackExcutor。方法内部创建了ExecutorCallAdapterFactory类实例,并返回该实例的List。
  • defaultConverterFactories()方法,返回了OptionalConverterFactory实例,此类中的转换converter()方法只检查了参数是否为空就将其返回了,说明默认的回调数据是不进行任何转换的。

至此,三个默认参数已确定。

获得自定义接口对象

IHttpRequestTest iHttpRequestTest = retrofit.create(IHttpRequestTest.class);
这是接下来的执行步骤,自定义接口对象由retrofit类中的create方法创建,进去探讨一下。

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();
          private final Object[] emptyArgs = new Object[0];

          @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);
            }
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });
  }

该方法返回的是通过反射获得自定义接口的代理类,并在类中重写了invoke方法。这表明当该类中的方法被执行时,就会拦截此方法。

拦截并解析方法。

Call<BaseModel<ArrayList<Benefit>>> call = iHttpRequestTest.getBenefits(40, 2);
由上一步骤可知,当执行代理类中的方法时,会被拦截。并最终执行loadServiceMethod(method).invoke(args != null ? args : emptyArgs);方法并返回。先看一下loadServiceMethod(method)方法。

ServiceMethod<?> loadServiceMethod(Method method) {
    //serviceMethodCache,如果执行过此方法,就会有缓存存在这里,直接取出即可
    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(this, method)方法里。

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 T invoke(Object[] args);
}

这是一个抽象类,第一句RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);,是解析方法构建request参数的。RequestFactory类中内容比较多,简单讲一下就是通过获得方法注解、返回类型、方法参数,分别进行解析。

最后它又跑到HttpServiceMethod类中了。此类继承了ServiceMethod类。

static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method);
    Type responseType = callAdapter.responseType();

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

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

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

    return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
  }

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

    return retrofit.responseBodyConverter(responseType, annotations);
  }

简化了异常检测类代码,可以看到最后返回的是HttpServiceMethod类的实例对象,并将retrofit中的一些默认参数传了进去。

解析完了loadServiceMethod(method),接下来就是执行invoke方法了。由于loadServiceMethod(method)返回的是HttpServiceMethod类的实例对象,所以执行的就是HttpServiceMethod类中的invoke方法。

@Override ReturnT invoke(Object[] args) {
    return callAdapter.adapt(
        new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
  }

此方法很简单,调用了callAdapter中的adapt方法,参数是一个OkHttpCall,字面意思就是将OkHttpCall适配为其他类。那么这个类是什么什么呢。应该是我们需要返回的Call<BaseModel<ArrayList<Benefit>>>类。那么怎么适配的呢。上面我们已经说到,retrofi中的默认参数callAdapterFactoriesExecutorCallAdapterFactory类,而callAdapterFactories中的callAdapter是通过callAdapterFactories.get()获得的,那么就要去这里面找了。

@Override public @Nullable CallAdapter<?, ?> get(
      Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    final Type responseType = Utils.getCallResponseType(returnType);
    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call<Object> adapt(Call<Object> call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }

返回的CallAdapter对象就是我们需要的。其中重写了adapt方法,也是我们要找的。它又返回了ExecutorCallbackCall对象,第一个参数就是默认运行在主线程中的callbackExecutor,第二个参数则是调用时传进来的OkHttpCall对象。所以说我们需要返回的Call<BaseModel<ArrayList<Benefit>>>对象就是ExecutorCallbackCall对象。

依靠OkHttp3进行网络请求,转换回调函数线程到主线程。

call.enqueue(new Callback<BaseModel<ArrayList<Benefit>>>() {...});,终于到最后一步了,拿着上一步返回的Call<BaseModel<ArrayList<Benefit>>>对象进行异步请求。调用了enqueue方法,也就是ExecutorCallbackCall中的enqueue方法。

ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }
    @Override public void enqueue(final Callback<T> callback) {
      checkNotNull(callback, "callback == null");
      delegate.enqueue(new Callback<T>() {
        @Override public void onResponse(Call<T> call, final Response<T> response) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              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(new Runnable() {
            @Override public void run() {
              callback.onFailure(ExecutorCallbackCall.this, t);
            }
          });
        }
      });
    }

构造方法给了出来,变量名有些转换。callbackExecutor依然是在主线程中的那个callbackExecutordelegate是上一步传进来的OkHttpCall对象。而enqueue的参数callback则是我们自己传入的callback。

方法中首先是delegate也就是OkHttp3进行的异步请求,在回调的函数中,通过callbackExecutor使线程切换为主线程,再调用我们自己的callback中对应的函数,使我们可以再回调中进行操作,并且是在主线程中。

OkHttpCall这个类就不在多讲了,主要作用是retrofit通过OkHttp3进行请求的一个转换。

结语

第一次分析源码,虽然有视频的帮助,但许多类之间跳来跳去的让人眼花缭乱,很艰难地顺了下来。有了这样一个大概的了解,接下来就要分析其设计模式,欣赏其漂亮的解耦套路。当然,如果你已经有了上面的了解,接下来看Retrofit分析-经典设计模式案例就会简单明了。


   转载规则


《Retrofit源码分析》 飞跃 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
每日一道面试题(第1期)---自定义handler如何有效保证内存泄漏问题 每日一道面试题(第1期)---自定义handler如何有效保证内存泄漏问题
零零碎碎的东西总是记不长久,仅仅学习别人的文章也只是他人咀嚼后留下的残渣。无意中发现了这个每日一道面试题,想了想如果只是简单地去思考,那么不仅会收效甚微,甚至难一点的题目自己可能都懒得去想,坚持不下来。所以不如把每一次的思考、理解以及别人
2020-03-31
下一篇 
2019年终总结 2019年终总结
踩着2019年的尾巴,也来做一下这一年的总结。三年多的大学时光确实稍纵即逝,不知不觉大四也已经过了大半,想想大一刚入学时对大学生活的憧憬,现在回过头来,确实差强人意。平平淡淡,一个普普通通的大学生拥有的大学生活,仅此而已。
2019-12-31
  目录