Retrofit2.0源碼解析

最近看了一下Retrofit2的源碼,感覺並不是很難,但是對於其中的設計方式大爲讚歎,怪不得會成爲現在最流行的網絡請求框架,Retrofit感覺就像是一個包裝殼,我不幹請求這種髒話,還是你okhttp幹吧,畢竟你做得好,在內部來說我就是專門給你檢查檢查一些url接口的規範,或是是一些Request,你就專心幹你的請求就行,對於外部使用者來說,我什麼都給你封裝好了,你要啥我就給你啥,你想要什麼類型的結果數據我就給你什麼樣的數據,你不要管我幹了什麼,這種不管不問的方式,我還是挺喜歡的。


下面貼出Retrofit的基本使用,然後跟着這個基本結構去分析源碼,這樣,有利於去探索。

public interface APIServer {
    @GET("/")
    Call<ResponseBody> getText();
 }
      Retrofit rv = new Retrofit.Builder()
                .baseUrl("http://www.lontano.wang/")
                .build();

        APIServer apiServer = rv.create(APIServer.class);
        Call<ResponseBody> call = apiServer.getText();
        call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                response.toString()
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {

            }
        });

這是最基本的請求步驟了,接下來一步步的分析。

初始化

我們來看看初始化

Retrofit rv = new Retrofit.Builder()
                .baseUrl("http://www.lontano.wang/")
                .build();

先看看內部建造者Builder類的初始化,下面有一個Platform類,這個類是用來獲取當前的使用平臺,有默認值,java8平臺,還有Android平臺。最下面默認還添加了一個BuiltInConverters,這個是默認的覆蓋結果的類,我們常常在請求返回結果類型的時候希望返回一個處理好的bean,所以,我們使用Retrofit的時候喜歡用GsonConverterFactory.create(),如果使用者沒有添加(就像我上面的例子)的話就是用默認值,這個類覆蓋結果的是一個String類型的結果,所有覆蓋結果類都繼承了Retrofit的Converter.Factory類,並對結果進行轉換。

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

接下來看看baseUrl方法,這個方法主要用來檢查這個鏈接是否正確,然後是區分是http還是https,然後並對這個鏈接進行再一次拼接。主要操作都在HttpUrl這個類裏面

   public Builder baseUrl(String baseUrl) {
      checkNotNull(baseUrl, "baseUrl == null");
      HttpUrl httpUrl = HttpUrl.parse(baseUrl);
      if (httpUrl == null) {
        throw new IllegalArgumentException("Illegal URL: " + baseUrl);
      }
      return baseUrl(httpUrl);
    }

然後看build方法,這個方法主要就是對剛剛設置build參數做最後的總結,我們來看看這個callFactory,因爲Retrofit把okHttp都封裝好了,我們根本無法對他進行設置,比如,我要用session去請求,而且我還要設置請求頭或是請求時間,但是我接觸不到okHttp啊,所以,這個時候,我們可以通過Build的 public Builder client(OkHttpClient client) 將需要設置okHttp的設置帶進來,下面的這個callFactory如果爲null的話,就默認初始化一個,

 public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }
      //-------callFactory
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }
//is not used for addCallAdapterFactory custom method return types
      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));

    /*返回類型添加到集合中,這個地方比較常見的就是RxJava,可以通過build方法的  
        addCallAdapterFactory(RxJava2CallAdapterFactory.create())將返回類型進行轉換
    */
      // Make a defensive copy of the converters.
      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

//返回給Retrofit類
      return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
          callbackExecutor, validateEagerly);
    }
  }

使用

好了,Build的過程結束了,這個返回的new Retrofit也無處看了,也都是剛纔的值,設置到Retrofit的全局去了,恩,我們接下來直接看使用方法了,來看看

  APIServer apiServer = rv.create(APIServer.class);

這個類纔是最核心的地方,我們點進去看看,這個類使用了動態代理,在原來調用的方法中,添加一些自己的處理,這個動態代理主要乾了些什麼呢?

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);
            }
            //這個處理也不看,只有平臺是java8的時候纔有用
            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方法,這個方法主要功能就是通過註解解析調用方法一些請求信息,將這些信息緩存起來,下次調用的時候直接拿,這個方法調用了loadServiceMethod來返回一個ServiceMethod,我們來看看這個方法。

ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);

首先是一個判斷當前緩存是否有該方法,沒有的話就去初始化,初始化類用的是ServiceMethod.Builder去構建的,並將Retrofit引用和方法信息傳遞過去。

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

我們來看看ServiceMethod.Builder的build方法幹了些什麼,因爲代碼過長,我把主要的代碼拎出來。

 /*首先創建一個CallAdapter,這個類主要檢查一些註解的規範,比如方法的修飾不能爲void,必須要有返回值,然後獲取該方法的註解信息,
Retrofit繼續調用 return nextCallAdapter(null, returnType, annotations)方法,
該方法通過遍歷類型CallAdapter.Factory的集合獲取對應的CallAdapter,對於這個CallAdapter我們有一個非常常見的使用,那就是
addCallAdapterFactory(RxJava2CallAdapterFactory.create()),
我們在使用RxJava來作爲返回類型的時候,就是這樣爲Retrofit來添加一個返回類型的,所以,
此處如果開發者使用了RxJava類返回類型的話,那麼這個地方所創建的返回類型就是RxJava返回的類型,
*/

     callAdapter = createCallAdapter();

    //此處去獲取CallAdapter的響應類型,這個responseType還使用了檢測,不能使用Response.class ,

    responseType = callAdapter.responseType();

    //獲取方法的註解和返回類型,返回給Retrofit的  return retrofit.responseBodyConverter(responseType, annotations);
//然後返回return (Converter<ResponseBody, T>) converter;
    //這個地方比較常見的就是addConverterFactory(GsonConverterFactory.create())添加覆蓋的返回類型爲Gson

   responseConverter = createResponseConverter();

  //這個parseMethodAnnotation方法應該是大家最常用的了,這個方法是獲取請求方法的註解,
  //Retrofit支持的請求有DELETE、GET、HEAD、PATCH、POST、PUT、OPTIONS等等,通過instanceof來判斷當前的類型,
  //然後調用parseHttpMethodAndPath來檢查註解的參數,並賦給全局,這個地方有個檢查,當使用Multipart註解的時候,必須是PATCH、POST、PUT、OPTIONS來修飾,
  //如果使用GET請求的話,不能用他來修飾,和他一樣的還是FormUrlEncoded,這兩個在平時使用的時候,都是和POST一塊使用
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }

     //
      for (int p = 0; p < parameterCount; p++) {
      //獲取參數類型
        Type parameterType = parameterTypes[p];

    //獲取參數的註解
     Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
     //創建ParameterHandler對象來存放檢查過後的參數和註解,這個方法中會對
     //Path、Query、QueryName、QueryMap、Header、HeaderMap、Field、FieldMap、Part、PartMap、Body來進行一些規範的檢查
   parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
         }  


最後將當前的引用信息返回ServiceMethod類return new ServiceMethod<>(this);

好了,最關鍵的ServiceMethod終於結束了,果然是重中之中,然後我們返回到Retrofit的代理中繼續接下來的操作。

//這個類封裝了OkHttp的enqueue和execute,執行enqueue方法會調用okhttpenqueue方法,
//通過回調的方式,將okHttp請求的結果回調給Retrofit,然後回調給用戶
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);

//返回callAdapter的類型,如果添加了RxJava2CallAdapterFactory,
//那麼就返回RxJava類型,然後就可以通過subscribe訂閱的方式實現鏈式調用
            return serviceMethod.callAdapter.adapt(okHttpCall);

至此,Retrofit的源碼大致分析如此,最後來個整體的總結。

總結

1.通過Retrofit.Builder()構建baseUrl,類型的覆蓋(addConverterFactory),請求結果轉換(addCallAdapterFactory)
2. 通過create(APIServer.class)實現動態代理APIServer類的處理
3. apiServer.getText()動態代理方法的執行
4. 處理ServiceMethod,並對一些註解進行規範化檢查,將結果緩存起來
5. 創建OkHttpCall通過okHttp去處理請求結果
6. serviceMethod.callAdapter.adapt返回結果類型

附錄

最後附上compile庫,以後添加的時候好用一些,RxAndroid、OkHttp,RxJava,Gson,RxBinding,Rxpermissions全家桶

    compile 'io.reactivex.rxjava2:rxjava:2.0.0'
    compile 'io.reactivex.rxjava2:rxandroid:2.0.0'
    compile 'org.reactivestreams:reactive-streams:1.0.0'
    compile 'com.squareup.okhttp3:okhttp:3.4.1'
    compile 'com.squareup.okio:okio:1.10.0'
    compile 'com.squareup.retrofit2:retrofit:2.1.0'
    compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
    compile 'com.squareup.retrofit2:converter-gson:latest.release'

    compile 'com.jakewharton.rxbinding2:rxbinding:2.0.0'
    compile 'com.jakewharton.rxbinding2:rxbinding-support-v4:2.0.0'
    compile 'com.jakewharton.rxbinding2:rxbinding-appcompat-v7:2.0.0'
    compile 'com.jakewharton.rxbinding2:rxbinding-design:2.0.0'
    compile 'com.jakewharton.rxbinding2:rxbinding-recyclerview-v7:2.0.0'
    compile 'com.jakewharton.rxbinding2:rxbinding-leanback-v17:2.0.0'

    compile 'com.tbruyelle.rxpermissions2:rxpermissions:0.9.3@aar'
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章