Retrofit 源碼剖析-深刻

背景

前一章節,先系統的講解了關於Retrofit實現當中的主要技術動態代理,本篇詳細結合動態代理在Retrofit中的應用,擴展到結合RxJava來使用html

Retrofit源碼解析-動態代理java

思路

要深刻研究一款開源項目最好的入口就是它所暴露出來的外部使用接口,按照這個思路,因此須要大致先了解Retrofit的基本使用,這裏就不闡述這些基礎的知識,能夠查看之前的博客git

RxRetrofit-專欄github

項目分析

想要弄清楚 Retrofit 的細節,先來看一下 Retrofit 源碼的組成:設計模式

這裏寫圖片描述

  • 一個 retrofit2.http 包,裏面所有是定義 HTTP 請求的註解,好比 GET、POST、PUT、DELETE、Headers、Path、Query 等等數組

  • 餘下的 retrofit 2.0 包中十幾個類和接口就是所有 retrofit 的代碼了,代碼真的不多,很簡單,由於retrofit把網絡請求這部分功能所有交給了 okHttp 了緩存

初始對象

先上一段使用Retrofit開始前的初始代碼網絡

//手動建立一個OkHttpClient並設置超時時間緩存等設置
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        builder.connectTimeout(basePar.getConnectionTime(), TimeUnit.SECONDS);

        /*建立retrofit對象*/
        Retrofit retrofit = new Retrofit.Builder()
                .client(builder.build())
                .addConverterFactory(ScalarsConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .baseUrl(basePar.getBaseUrl())
                .build();複製代碼

這裏的入口Builder()方法進入源碼ide

public static final class Builder {
    private Platform platform;
    private okhttp3.Call.Factory callFactory;
    private HttpUrl baseUrl;
    private List<Converter.Factory> converterFactories = new ArrayList<>();
    private List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
    private Executor callbackExecutor;
    private boolean validateEagerly;

    Builder(Platform platform) {
      this.platform = platform;
      // 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());
    }

    public Builder() {
      this(Platform.get());
    }
xxxx複製代碼

Builder類中主要是記錄請求過程當中的一些配置信息,好比基礎url,固然重要的是addConverterFactory方法記錄Converter數據轉換器;addCallAdapterFactory方法記錄CallAdapter-HTTP請求返回數據的類型.工具

Converter數據轉換器

Converter數據轉換器默認存放在retrofit-converters

這裏寫圖片描述

Converter採用接口抽象的方式,靈活了轉換器的種類,經常使用的如上圖中的GsonString,一樣這裏能夠能夠自由擴展,實現Converter.Factory接口

CallAdapter請求返回數據的類型

工程位置如圖

這裏寫圖片描述

這裏同Converter數據轉換器思想同樣一樣是採用抽象接口的方式,繼承CallAdapter.Factory類實現擴展,正如上圖中箭頭指示的顯示擴展的RxJava2的擴展

信息的轉換

Builder記錄完數據後經過build()方法,將收集的信息傳遞給最後的Retrofit對象中,而且初始了okhttp3.Call.Factory請求處理類,從中能夠看出Retrofit2.0底層的http請求默認就是經過okhttp3處理的。

/** * 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.");
      }

      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }

      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));

      // 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初始完成之後,須要調用create方法傳入一個java接口抽象類對象做爲參數。其實這一步真是Retrofit動態代理生成的地方

源碼:

@SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
  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);
            }
            ServiceMethod serviceMethod = loadServiceMethod(method);
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }複製代碼

使用代碼:

HttpTestService httpService = retrofit.create(HttpTestService.class);
        httpService.getAllVedioBy(isAll());複製代碼

上面HttpTestService對象實際上是一個動態代理對象,並非一個真正的 HttpTestService接口的implements對象,當 httpService對象調用 getAllVedioBy方法時,執行的是下面動態代理方法。

ServiceMethod serviceMethod = loadServiceMethod(method);
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);複製代碼

其中主要ServiceMethod是主要的處理對象

ServiceMethod信息類

當調用loadServiceMethod方法,將抽象HttpTestService中經過註解定義的信息收集起來存放於ServiceMethod中,其中主要包含了一下數據:

  • OkHttpClient:發送網絡請求的工具

  • RequestFactory: 相似於 Volley 中的 Request,包含了HTTP請求的Url、Header信息,MediaType、Method以及RequestAction數組

  • CallAdapter:HTTP請求返回數據的類型

  • Converter:數據轉換器

最後Map<Method, ServiceMethod> serviceMethodCache保存所有的 ServiceMethod信息類

ServiceMethod<?, ?> loadServiceMethod(Method method) {
    ServiceMethod<?, ?> result = serviceMethodCache.get(method);
    if (result != null) return result;

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = new ServiceMethod.Builder<>(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }複製代碼

debug可查看當前ServiceMethod對象收集的信息

這裏寫圖片描述

收集完信息之後執行了

OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);複製代碼

這一步對okhttp熟悉的同窗確定知道了,就是經過okhttp請求數據,其中serviceMethod是請求的地址信息,args是當前接口須要的參數信息。

執行完http請求之後,執行了

serviceMethod.callAdapter.adapt(okHttpCall);複製代碼

這一步是將okhttp獲取到的數據傳遞給一開始Retrofit經過builder指定的RxJavaCallAdapterFactory類,那它是如何一步步處理的呢?

其實在一開始的獲取serviceMethod方法loadServiceMethod(Method method)中,已經將Retrofit對象傳遞給了serviceMethod對象

核心代碼:

//這裏的this便是`Retrofit`對象
result = new ServiceMethod.Builder(this, method).build();複製代碼

經過.Builder(this, method).build()方法將Retrofit一開始的builder信息所有傳遞給瞭如今的serviceMethod對象,因此當執行

serviceMethod.callAdapter.adapt(okHttpCall);複製代碼

serviceMethod.callAdapter便制動轉換成了RxJavaCallAdapterFactory,調用CallAdapter抽象接口adapt進入到RxJavaCallAdapterFactory類中

源碼:

@Override public <R> Observable<Response<R>> adapt(Call<R> call) {
      Observable<Response<R>> observable = Observable.create(new CallOnSubscribe<>(call));
      if (scheduler != null) {
        return observable.subscribeOn(scheduler);
      }
      return observable;
    }
  }複製代碼

最後生成RxJavaObservable對象,後面經過獲得的Observable對象就是對數據的處理了。

到此基於Retrofit結合RxJava源碼的解讀就完成了,回頭看整個過程其實仍是很簡單,做者條理清晰理解起來也很簡單,一口氣終於把Retrofit大致擼了一遍。

總結

Retrofit 很是巧妙的用註解來描述一個 HTTP 請求,將一個 HTTP 請求抽象成一個 Java 接口,而後用了 Java 動態代理的方式,動態的將這個接口的註解「翻譯」成一個 HTTP 請求,最後再執行這個 HTTP 請求

Retrofit的功能很是多的依賴 Java 反射,代碼中其實還有不少細節,好比異常的捕獲、拋出和處理,大量的 Factory 設計模式。

Retrofit 中接口設計的恰到好處,在你建立 Retrofit 對象時,讓你有更多更靈活的方式去處理你的需求,好比使用不一樣的 Converter、使用不一樣的 CallAdapter,這也就提供了你使用 RxJava 來調用 Retrofit 的可能。

專欄

RxJava+Retrofit+OkHttp深刻淺出-終極封裝專欄)

源碼

retrofit2.0

建議

若是你有任何的問題和建議歡迎加入QQ羣告訴我!

相關文章
相關標籤/搜索