Retrofit源码解析

前边OkHttp的源码顺藤摸瓜,摸了个遍。但是我们用的比较多的还是Retrofit,都是square的佳作,它是在OKHttp上进行了封装,对开发者变得更加友好。本文基于retrofit: 2.9.0开撸。

一、Retrofit在OKHttp上新增了什么魔法

  • 使用动态代理模式使用接口和注解方式定义请求方法,对应用层友好,使用容易理解和方便
  • 它可以和RxJava配合使用,超级解耦
  • 它可以定制很多解析转换器,来将接口返回的数据封装为我们的JavaBean对象
  • 在请求回来后,它会自动切换为主线程,无需额外在应用内部进行线程的切换

二、Retrofit的基本用法

Retrofit用法其实也不用多讲,很简单:

    1. 首先,新建个请求接口类
interface TestRetrofitService {

    @GET("test")
    fun getTestParms(): Call<ResponseBody>
}
    1. 再构建一个全局的Retrofit实例,它也是基于建造者模式
var retrofit: Retrofit = Retrofit.Builder().baseUrl("http://www.baidu.com").build()
    1. 然后使用Retrofit实例动态生成一个请求接口的代理对象
var testRetrofitService: TestRetrofitService = retrofit.create(TestRetrofitService::class.java)

*4. 使用代理对象调用请求接口方法,生成一个Call对象

val testCall: Call = testRetrofitService.getBaiduParms();
    1. 调用Call的enqueue方法,发起异步请求,execute方法则是同步请求
     testCall.enqueue(object: retrofit2.Callback<ResponseBody>{
            override fun onFailure(call: retrofit2.Call<ResponseBody>, t: Throwable) {
                TODO("Not yet implemented")
            }

            override fun onResponse(call: retrofit2.Call<ResponseBody>, response: retrofit2.Response<ResponseBody>) {
                TODO("Not yet implemented")
            }

        })

三、Retrofit是如何通过建造者模式实例化的?

Retrofit.Builder().baseUrl("http://www.baidu.com").build()
    1. Retrofit有个Builder内部类,它有两个构造方法,它会传入平台类,并通过jvm虚拟机的名字判断是Android平台还是Java平台。
   Builder(Platform platform) {
      this.platform = platform;
    }

    public Builder() {
      this(Platform.get());
    }
  private static Platform findPlatform() {
    return "Dalvik".equals(System.getProperty("java.vm.name"))
        ? new Android() //
        : new Platform(true);
  }
    1. 然后通过Retrofit.Builder实例可以传入很多配置参数,这和OKHttp一致,最后通过build()方法,实例化Retrofit
    public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }

      ...

      return new Retrofit(
          callFactory,
          baseUrl,
          unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories),
          callbackExecutor,
          validateEagerly);
    }

四、Retrofit是如何通过动态代理实例化请求接口类的代理对象?

//请求接口类
interface TestRetrofitService {

    @GET("meinv")
    fun getBaiduParms(): Call<ResponseBody>
}

//通过动态代理实例化一个代理对象
var testRetrofitService = retrofit.create(TestRetrofitService::class.java)

跟踪Retrofit.create()方法,映入眼前的就是妥妥的动态代理模式了,Proxy.newProxyInstance()。通过动态代理返回了一个TestRetrofitService接口类的代理对象

  public <T> T create(final Class<T> service) {
    return (T)
        Proxy.newProxyInstance(
            service.getClassLoader(),
            new Class<?>[] {service},
            new InvocationHandler() {
              ...
              @Override
              public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
                  throws Throwable {
                ...
158行                return platform.isDefaultMethod(method)
                    ? platform.invokeDefaultMethod(method, service, proxy, args)
                    : loadServiceMethod(method).invoke(args);
              }
            });
  }

五、Retrofit生成的动态代理对象调用请求方法后,如何返回的Call对象的?

val testCall: Call = testRetrofitService.getBaiduParms();

    1. 我们可以看到上面动态代理158行,这里又是Android和java平台的判断,这里直接可以看到
loadServiceMethod(method).invoke(args)
    1. 在loadServiceMethod()方法中,它将对传入的Method的注解进行解析保存为一个ServiceMethod对象并缓存起来。
  ServiceMethod<?> loadServiceMethod(Method method) {
    //1. 首先冲缓存中获取,获取到了就返回
    ServiceMethod<?> result = serviceMethodCache.get(method);
    if (result != null) return result;

    //2. 为了线程安全问题,加了锁
    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        //3. 开始解析Annotations
        result = ServiceMethod.parseAnnotations(this, method);
        //4. 将解析好的serviceMethod缓存起来
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }
    1. ServiceMethod是一个抽象类,HttpServiceMethod为其子类
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
26行    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);

    Type returnType = method.getGenericReturnType();
   ...

    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }
    1. 如上26行,它通过RequestFactory类的parseAnnotations()方法解析请求接口类的方法上和参数的注解。

在RequestFactory里实际也是通过建造者模式,返回了RequestFactory实例

 static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
    return new Builder(retrofit, method).build();
  }

通过查看Builder内部类中的build方法,发现了很多解析Annotation注解的方法。

    RequestFactory build() {
      for (Annotation annotation : methodAnnotations) {
181行        parseMethodAnnotation(annotation);
      }
      ...

      int parameterCount = parameterAnnotationsArray.length;
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
205行        parameterHandlers[p] =
            parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
      }

     ...
      return new RequestFactory(this);
    }

181行解析的是方法上的注解:这里大家看着都懂,无非就是解析方法上的一个@GET、@POST等注解,并获取值,并保存在成员变量中

private void parseMethodAnnotation(Annotation annotation) {
      if (annotation instanceof DELETE) {
        parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
      } else if (annotation instanceof GET) {
        parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
      }
  ...
}

205行解析的是方法上的注解:这里就是将方法里的每个参数单独保存为一个ParameterHandler实例

    private @Nullable ParameterHandler<?> parseParameter(
        int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
      ParameterHandler<?> result = null;
      if (annotations != null) {
        for (Annotation annotation : annotations) {
          ParameterHandler<?> annotationAction =
              parseParameterAnnotation(p, parameterType, annotations, annotation);
   ...
}

后续的如何解析,大家可以深入代码中看看,这里就不一一贴代码了。比较简单,就是注解的解析取值,存值过程。

    1. 前边的ServiceMethod.parseAnnotations()方法最终返回了一个HttpServiceMethod实例,而HttpserviceMethod是ServiceMethod的子类
 static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
    ...
    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }
    1. 回到第2点,动态代理最终返回的是loadServiceMethod(method).invoke(args),而loadServiceMethod(method)返回的是一个HttpServiceMethod的实例,我们看看它的invoke()方法,这里就实例化了一个OKHttpCall对象,而它就是Call的子类。这里其实它还被另外一个ExecutorCallbackCall包装了一层(adapt(call, args)方法包装)。这里先不讲。
  final @Nullable ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
  }

六、Retrofit如何通过Call实例对象发起请求的?

   testCall.enqueue(object: retrofit2.Callback<ResponseBody>{
        override fun onFailure(call: retrofit2.Call<ResponseBody>, t: Throwable) {
            TODO("Not yet implemented")
        }

        override fun onResponse(call: retrofit2.Call<ResponseBody>, response: retrofit2.Response<ResponseBody>) {
            TODO("Not yet implemented")
        }

    })

前面知道了其实真正执行请求的Call就是OKHttpCall,我们跟踪enqueue()方法进去看看。

    1. 调用OKHttpCall.enqueue()方法
  @Override
  public void enqueue(final Callback<T> callback) {
    okhttp3.Call call;
    synchronized (this) {
      call = rawCall;
      if (call == null && failure == null) {
        try {
130行          call = rawCall = createRawCall();
        } catch (Throwable t) {
        }
      }
    }

147行    call.enqueue(
        new okhttp3.Callback() {
          @Override
          public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
              callback.onResponse(OkHttpCall.this, response);
          }

          @Override
          public void onFailure(okhttp3.Call call, IOException e) {
            callback.onFailure(OkHttpCall.this, e);
          }
        });
  }
    1. 它在130行调用了createRawCall()方法,它调用了callFactory.newCall方法创建出okHttp3.Call对象
private okhttp3.Call createRawCall() throws IOException {
    okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
   ...
    return call;
  }
    1. 这里的callFactory实际上就是OKHttpClient,这在之前建造者模式创建Retrofit实例的build()方法中可以看到,而OkHttpClient.newCall()方法实际上就是返回了一个RealCall对象
public Retrofit build(){
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }
...
}
  @Override public Call newCall(Request request) {
    return RealCall.newRealCall(this, request, false /* for web socket */);
  }
    1. requestFactory.create(args)方法呢,就是返回了一个Request请求对象。
  okhttp3.Request create(Object[] args) throws IOException {
    @SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
    ...

    RequestBuilder requestBuilder =
        new RequestBuilder(
            httpMethod,
            baseUrl,
            relativeUrl,
            headers,
            contentType,
            hasBody,
            isFormEncoded,
            isMultipart);

    ...

    return requestBuilder.get().tag(Invocation.class, new Invocation(method, argumentList)).build();
  }
    1. 回到1中的147行,call.enqueue()实际就是使用OKHttp的ReallCall对象开始将请求进行分发,或加入执行队列或加入等待队列。这里和之前写的《OKHttp源码解析》请求流程一致了。然后在回调接口。

七、Retrofit如何在返回response时,切换到主线程可以直接渲染UI的?

这里讲起来有点绕:

    1. 先回到Retrofit的创建来,在Build.buid()方法中,它会为Retrofit默认添加平台默认的CallAdapter适配器工厂,如android平台就添加Android类中的callbackExecutor(PS: Android是platform的子类,实现了defaultCallbackExecutor方法)
public Retrofit build() {
...
 Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
631行        callbackExecutor = platform.defaultCallbackExecutor();
      }
      638行 callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
...
}
    1. 631行获取了平台默认的回调执行器,这里就是线程切换的地方,而Android是Platform内部子类。它返回了一个MainThreadExecutor()对象,而它实际上就是通过new Handler(Looper.getMainLooper()),Handler来实现切回主线程。
  static final class Android extends Platform {


    @Override
    public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

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

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

八. 实际上这里已经知道Retrofit怎么切换到主线程了,那么它在哪里调用的呢?

    1. 在 上面七的638行,platform.defaultCallAdapterFactories(callbackExecutor)它通过传入callBackExecuter,返回了一个平台默认的CallAdapterFactory适配器工厂。它实际上就是返回了一个DefaultCallAdapterFactory。
  List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
      @Nullable Executor callbackExecutor) {
    DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
    return hasJava8Types
        ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
        : singletonList(executorFactory);
  }
    1. 前边我们说在HttpServiceMethod.invoke()返回的是一个OKHttpCall对象,其实不完全对,因为它还被CallAdapter适配器包装了一层。
  @Override
  final @Nullable ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
  }

    @Override
    protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
      return callAdapter.adapt(call);
    }
    1. 2中所说的CallAdapter适配器就是通过DefaultCallAdapterFactory工厂的get()方法生成的。
      至于如何生成,给一个路线(是在动态代理生成代理对象,并通过代理对象调用请求方法时):
1. ServiceMethod.parseAnnotations()
2.HttpServiceMethod.parseAnnotations()
    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
3. HttpServiceMethod.createCallAdapter()
4. Retrofit.callAdapter()
5. Retrofit.nextCallAdapter()
    public CallAdapter<?, ?> nextCallAdapter(
      CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {
      ...
      for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
        CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
        return adapter;
     }
    }
    1. 看到DefaultCallAdapterFactory.get()方法,它返回了一个CallAdapter对象。
  public @Nullable CallAdapter<?, ?> get(
      Type returnType, Annotation[] annotations, Retrofit retrofit) {
    ...
 47行   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);
      }
    };
  }
    1. 47行:callbackExecutor实际就是1中的MainThreadExecutor,最后return CallAdapter,在CallAdapter的adapt方法中返回了一个ExecutorCallbackCall对象
new ExecutorCallbackCall<>(executor, call)
    1. 这个传入的参数call就是OKHttpCall, 而ExecutorCallbackCall就是包装OKHttpCall的,它主要用来回调时做线程切换用途的。它也是call的子类。它是DefautlCallAdapterFactory内部类
 static final class ExecutorCallbackCall<T> implements Call<T> {

    @Override
    public void enqueue(final Callback<T> callback) {
      //1. delegate就是OKHttpCall,实际上就是OKHttpCall.enqueue()
      delegate.enqueue(
          new Callback<T>() {
            @Override
            public void onResponse(Call<T> call, final Response<T> response) {
              //2. 请求返回后使用MainThreadExecutor对象切换线程
              callbackExecutor.execute(
                  () -> {
                    if (delegate.isCanceled()) {
                      // 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));
            }
          });
    }
}
  1. delegate就是OKHttpCall,实际上就是OKHttpCall.enqueue()
  2. 请求返回后使用MainThreadExecutor对象切换线程
              callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));

九、结语

我们通过Retrofit的主线了解清楚了,Retrofit如何通过动态代理和注解反射等机制对OKHttp进行封装。对于我们灵活使用Retrofit来开发和解决使用Retrofit中遇到的问题非常有帮助,另外也通过跟踪框架源码,对于搭建框架也有了更多的认识和理论支撑。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,837评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,551评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,417评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,448评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,524评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,554评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,569评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,316评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,766评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,077评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,240评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,912评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,560评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,176评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,425评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,114评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,114评论 2 352

推荐阅读更多精彩内容