Retrofit2源码分析

来源:互联网 发布:湘阴农村淘宝招聘信息 编辑:程序博客网 时间:2024/06/09 21:49

前言

很长一段时间没有写博客,主要原因是工作了感觉没什么时间了(其实是因为懒)。最近在项目中引用了 Retrofit+Rxjava 组合,感觉写的非常刺激。秉着不单单只停留在会用的层次上,还需要对源码进行分析的理念,决定是时候学(zhuang)习(bi)一波了。

此篇博客所需知识

  1. 对 适配器模式 有一定的了解。
  2. 会使用 Retrofit 以及 Rxjava
  3. 知道如何优雅的装逼,故意把一个简单的东西说的很复杂。

Retrofit 使用例子

Retrofit retrofit = new Retrofit.Builder()            .addConverterFactory(GsonConverterFactory.create())//          .addCallAdapterFactory(RxJavaCallAdapterFactory.create())            .baseUrl("http://gc.ditu.aliyun.com/")            .build();MyService service = retrofit.create(MyService.class);Call<City> call = service.getCity("汕头市");call.enqueue(new Callback<City>() {    @Override    public void onResponse(Call<City> call, Response<City> response) {        Log.e("cat", "response:" + response.body().toString());    }    @Override    public void onFailure(Call<City> call, Throwable t) {        t.printStackTrace();        Log.e("cat", "fail:" + t.getMessage());    }});

上述代码就是我们使用 Retrofit 的典型代码,对 Retrofit 这个库还不熟悉的请先自行去学习这个库,这篇博客不讲使用,只讲源码,这篇博客不讲使用,只讲源码,这篇博客不讲使用,只讲源码

源码分析

源码相关知识普及

在看其源码之前,首先有些东西得普及一下,以免跟踪源码的时候有些玩意不知道干什么用的。
首先,Retrofit 最开始会通过 Builder 模式 构造出一个 Retrofit 对象,大部分属性,一旦构造完,便不允许修改。当需要使用的时候,调用 Retrofit.create(Service.class) 初始化我们的业务对象。Retrofit.create() 方法内部使用的是动态代理模式,会拦截我们调用 Service 的每一个方法。为啥要拦截呢?主要是将 Service 接口 中的方法中的注解,封装成一个请求对象 OkHttpCall,并且使用适配器模式来对 OkHttpCall 进行适配,转换成我们需要的类型,例如 Observable。Retrofit 内部会保存有一个 Adapter 以及 Converter 的 list,封装请求对象的时候会遍历这两个集合,寻找适合这个请求的 Adapter 以及 Converter。
上述过程主要是请求的构建,同时 Retrofit 确实也不负责其他功能,其网络请求功能主要还是交给 OkHttp 去实现,依我看来,Retrofit 只是充当了一个粘合剂而已。

三个个重要的对象
1. CallAdapter: 主要是用来对 OkHttpCall 进行适配,常用的就是 RxJavaCallAdapterFactory,构造的时候不指定的话,默认实现是 ExecutorCallAdapterFactory 由工厂生成的。
2. Converter: 用来对后台返回的数据进行转换的转换器,一般后台会返回 json 数据,我们一般会使用 GsonConverterFactory 来进行转换。
3. ServiceMethod: 根据接口中的方法以及注解生成的对象,封装了对应方法的 converter 以及 adapter 等(注意,不同的方法可能有不同的 convertor 以及 adapter)。
4. OkHttpCall:这个东西我很难描述是什么东西,主要是用来执行请求的吧。用过 OkHttp 的应该知道。

构造 Retrofit

构造 Retrofit 采用的是 Builder 设计模式,我们直接点进去 build() 方法看看就好,因为中间的一系列链式调用无非就是一些赋值而已。

Retrofit.Builder.build()

  /**   * Create the {@link Retrofit} instance using the configured values.   * <p>   * Note: If neither {@link #client} nor {@link #callFactory} is called a default {@link   * OkHttpClient} will be created and used.   */  public Retrofit build() {    if (baseUrl == null) {      throw new IllegalStateException("Base URL required.");    }    // callFactory 是构造 Retrofit 时候调用 Buidler.callFactory() 进行赋值的,效果跟 Buidler.clien() 是相同的。    //如果在构造 Retrofit 时没有进行赋值,则默认采用的是 OkHttpClient    okhttp3.Call.Factory callFactory = this.callFactory;    if (callFactory == null) {      callFactory = new OkHttpClient();    }    // callbackExecutor 是构造 Retrofit 时候调用 Buidler.callbackExecutor() 进行赋值的。默认实现是将 Runnbale post 到主线程中执行。    Executor callbackExecutor = this.callbackExecutor;    if (callbackExecutor == null) {      callbackExecutor = platform.defaultCallbackExecutor();    }    // 对 adapterFactories 以及 converterFactories 进行保护性复制,防止由于类的外部持有 adapter 或者 convertor 的 引用从而能能在构造 Retrofit 后仍能从外部对其进行改变。    // 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));    // Make a defensive copy of the converters.    List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);    return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,        callbackExecutor, validateEagerly);  }}

创建完 Retrofit 后就需要实例化我们的业务对象 Service 了,点进去 Retrofit.create() 方法中看下。

初始化业务对象

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();        @Override public Object invoke(Object proxy, Method method, 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);          }          //上面两个 if 可以省略。下面这几句主要是将方法封装成一个请求对象以及对 okHttpCall 进行适配。          // 根据接口方法中的注解等封装成一个 serviceMethod          ServiceMethod serviceMethod = loadServiceMethod(method);          // 封装成一个请求对象。          OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);          // 对 okHttpCall 进行适配,转换成我们需要的返回值类型。          return serviceMethod.callAdapter.adapt(okHttpCall);        }      });}

这段代码主要是生成我们的业务对象,这是根据我们定义的接口返回来的代理对象,以后我们每次调用业务方法都会被其进行拦截,被其封装成一个请求对象,同时转换成我们需要的类型,这里由于我们没有指定 Adapter,所以采用的是 Retrofit 默认的 ExecutorCallAdapterFactory。

Retrofit.loadServiceMethod

ServiceMethod loadServiceMethod(Method method) {  ServiceMethod result;  // 查看是否有缓存对应 method 的 serviceMethod,有则直接取出,没有就重新生成一个 serviceMethod,并 put 进缓存 map 里面。  synchronized (serviceMethodCache) {    result = serviceMethodCache.get(method);    if (result == null) {      result = new ServiceMethod.Builder(this, method).build();      serviceMethodCache.put(method, result);    }  }  return result;}

ServiceMethod 的构建 #ServiceMethod.Buidler.build()

public ServiceMethod build() {  // 创建指定 method 的 adapter,内部实现是传入方法的返回值以及注解,遍历 Retrofit 中的 adapter list 进行匹配,通过工厂模式生成 adapter。 responseConverter 同理。  callAdapter = createCallAdapter();  responseType = callAdapter.responseType();  responseConverter = createResponseConverter();  //解析方法的注解,如 @Get @FormUrlEncode 这种注解,注意,不是参数的注解  for (Annotation annotation : methodAnnotations) {    parseMethodAnnotation(annotation);  }  // 解析方法**参数**中的注解  int parameterCount = parameterAnnotationsArray.length;  parameterHandlers = new ParameterHandler<?>[parameterCount];  for (int p = 0; p < parameterCount; p++) {    Type parameterType = parameterTypes[p];    if (Utils.hasUnresolvableType(parameterType)) {      throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",          parameterType);    }    Annotation[] parameterAnnotations = parameterAnnotationsArray[p];    parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);  }  ... 省略了对字段校验的代码  return new ServiceMethod<>(this);}

上面代码就完成了一个 ServiceMethod 对象的创建,当调用 ServiceMethod.toRequest 方法的时候,就生成了一个请求对象 Request

对 okHttpCall 进行适配

再次回到 Retrofit.create 方法,有如下一段。

return serviceMethod.callAdapter.adapt(okHttpCall);

serviceMethod 我们知道了,callAdapter 是什么呢?如果你在构造 Retrofit 不指定的话,默认实现就是 通过 ExecutorCallAdapterFactory 工厂生产出来的,来看一下这个类先。

final class ExecutorCallAdapterFactory extends CallAdapter.Factory {final Executor callbackExecutor;ExecutorCallAdapterFactory(Executor callbackExecutor) {  this.callbackExecutor = callbackExecutor;}// serviceMethod 生成 callAdapter 遍历 Retrofit 中的 adapter list  时会调用这个方法,这其实是个工厂方法,只不过这里只有一个实现,目测这破工厂也快倒闭了。RxJavaCallAdapterFactory 中有挺多实现的。@Overridepublic CallAdapter<Call<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {  if (getRawType(returnType) != Call.class) {    return null;  }  //实际的返回类型,即 Call 或者 Observable 包装的类型。  final Type responseType = Utils.getCallResponseType(returnType);  return new CallAdapter<Call<?>>() {    @Override public Type responseType() {      return responseType;    }    // 将 okHttpCall 进行包装,返回 Retrofit 的默认类型 ExecutorCallbackCall。这段其实就是 Retrofit 中的使用的适配器模式,将 Call 转换成我们想要的类型。    // 如果我们在构造 Retrofit 时指定了 CallAdapter 例如 Rxjava,则 adapt 会返回相应的类型。具体实现可以自行查看 RxJavaCallAdapterFactory    @Override public <R> Call<R> adapt(Call<R> call) {      return new ExecutorCallbackCall<>(callbackExecutor, call);    }  };}

上述方法就是系统默认的 ExecutorCallAdapterFactory,我们来看看其生成的 CallAdapter 是如何进行适配(adapt) 的。查看 adapt 方法返回的 ExecutorCallbackCall<>(callbackExecutor, call)

static final class ExecutorCallbackCall<T> implements Call<T> {final Executor callbackExecutor;final Call<T> delegate;//这里传入的 delegate 就是 okHttpCallExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {  this.callbackExecutor = callbackExecutor;  this.delegate = delegate;}// 其实就是把 enqueue 方法代理给 okHttpCall@Override public void enqueue(final Callback<T> callback) {  if (callback == null) throw new NullPointerException("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);        }      });    }  });}

这段没什么好说的,当我们调用 Call.enqueue 的时候,实际上调用的是 okHttpCall 的 enqueue。

总结

最后,再梳理一下。

  1. 首先,使用建造者模式生成一个 Retrofit。
  2. 生成我们的业务对象,调用 Retrofit.create 方法,通过动态代理模式返回一个代理对象,以后调用业务对象的任意一个方法, 都会被拦截。将 Service 接口中的每一个方法以及方法中的注解封装成一个请求对象。
  3. 封装请求对象的具体逻辑是,根据方法的返回值以及注解,遍历 Retrofit 中的 adapter list 以及 convertor list,通过工厂方法返回合适的 adapter 或者 convertor。然后,对 方法的注解进行解析,最后将解析后的结果、adapter 以及 convertor 封装成一个 serviceMethod。
  4. serviceMethod 封装后,会初始化一个 OkHttpCall ,这个对象就是真正执行请求的对象。
  5. 最后,调用 serviceMethod 的 adapter 的 adpt 方法对 okHttpCall 进行适配,返回我们想要的类型。例如 Observable。

Retrofit 这个库是一个巧妙的运用了各种设计模式的经典库,有许多地方值得我们学习。虽然能大概看懂其实现,但是要学会其中的思想,仍然需要一定时间的沉淀。同时,这个库比较容易读懂,绝对是我们进阶中级 Android 开发的良品。

1 0
原创粉丝点击