【遷移博客】retrofit源碼解析

在Android客戶端的項目網絡請求實踐中,對retrofit進行了實踐和源碼的閱讀。從retrofit的用法入手,對retrofit進行解析。 首先看一下retrofit的基本用法: 第一步建立retrofit對象:java

Retrofit retrofit = new Retrofit.Builder()
          .baseUrl(baseUrl)
          .build();
複製代碼

第二步建立一個service接口,接口的組成以下設計模式

public interface NetWorkService {
    @FormUrlEncoded
    @Post("/reativePath")
    Call<ResponseBody> getResponse(@Field("param") String param);
}
複製代碼

第三進行網絡請求緩存

NetWorkService service = retrofit.create(NetWorkService.class);
Call<ResponseBody> call = service.getResponse(param);
複製代碼

查看Retrofit的類結構,使用了經典的Builder設計模式,經過Builder的方法咱們一般能夠設置OkHttpClient、HttpUrl、ConverterFactory、CallAdapterFactory等。 查看Retrofit的create方法bash

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<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
複製代碼

這裏使用了Java的動態代理模式,關於代理模式和動態代理,能夠查看這裏。 在create中,建立了一個最終暴露給咱們的代理類A,類型爲T,也就是xxService,內部的委託類B爲service,也是咱們的類xxService。其中起到2個類的橋接做用的是一個實現了InvocationHandler接口的匿名類C,C爲A的委託類,爲B的代理類。最終A在外部對接口方法的調用會傳遞到C中,C再將調用傳遞給B。 在匿名類中網絡

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

這一段代碼就是在代理類中進行的調用。咱們進入這幾個方法能夠看到retrofit對於xxService的整個處理。 查看loadService的代碼ide

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);
     }
   }
複製代碼

在Retrofit類中維護了一個Map用來存放ServiceMethod,若是method對象已經存在就會使用已經存在的緩存對象,避免每次對象在代理類裏面運行的開銷。 進入ServiceMethod的build方法,咱們能夠看到retrofit對service的處理。我將service接口的處理過程梳理了一下post

  1. 建立CallAdapter
  2. 建立處理返回數據格式的Converter
  3. 解析方法上方的註解。例如@FormUrlEncoded、@Post
  4. 新建參數處理對象ParamterHandler
  5. 對service接口中的方法參數進行讀取和解析,在這裏,會對參數註解進行解析。

接下來咱們對每個步驟進行解析ui

###CallAdapter service的build中會調用retrofit的callAdapter方法,繼而調用nextCallAdapter方法。this

int start = adapterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = adapterFactories.size(); i < count; i++) {
      CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }
複製代碼

咱們會取出retrofit的存放adapter的list中第一個不爲空的adapter做爲最後使用的adapter,而且根據returntype去除CallAdapter,結合動態代理部分能夠看出,retrofit會把Call根據咱們的CallAdapter轉換爲想要的類型。例如retrofit+rxjava使用的時候把Call轉化爲一個Observable。編碼

Converter

接下來會執行createResponseConverter方法,這個主要是解析返回的數據。在裏面會調用retrofit的responseBodyConverter方法,相似callAdapter,接下來會調用nextResponseBodyConverter方法

int start = converterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = converterFactories.size(); i < count; i++) {
      Converter<ResponseBody, ?> converter =
          converterFactories.get(i).responseBodyConverter(type, annotations, this);
      if (converter != null) {
        //noinspection unchecked
        return (Converter<ResponseBody, T>) converter;
      }
    }
複製代碼

咱們會拿到retrofit中存放converter的list中第一個獲取到ConVerter對象不爲空的做爲方法的返回值。例如GsonResponseBodyConverter中就會把返回的response數據利用Gson解析爲對應的實體類對象。 並且在retrofit的Build類的build方法中,在存adapter的list裏面加入了默認的對象

adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
複製代碼

默認添加的是一個DefaultCallAdapterFactory對象 而converter的list則會默認添加一個BuiltInConverters對象

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());
    }
複製代碼

parseMethodAnnotation

接下來會對retrofit的xxService接口進行方法註解的解析 截取一小段代碼進行分析:

if (annotation instanceof POST) {
   parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
 }
複製代碼

其中最後一個參數的true和false是methodService中的hasBody變量 根據源碼咱們能夠將方法註解分類以下:

  1. Http方法 hasBody爲false
  • delete
  • get
  • head
  • options
  1. Http方法 hasBody爲true
  • patch
  • post
  • put
  1. 非http請求
  • Http
  • Headers
  • FormUrlEncoded
  • Multipart 其中FormUrlEncoded表示參數編碼爲表單,multipart爲文件上傳。2者互斥不得同時存在。 接下來會對方法參數的路徑進行解析以及驗證 若是方法註解爲headers,則表示裏面爲http頭信息,會單獨進行解析。

ParameterHandler

建立ParamterHandler對象,這個對象是用來處理參數的。在後面的request構建會使用到。其中,每個method的註解都有它對應的ParamterHandler對象。

parseParameter

在serviceMethod對象build前的最後一步是解析method的參數註解,會將讀取到的數據傳入ParamterHandler對象中,最終拼成http請求的參數

最後,在Retrofit的create中,咱們會返回一個Call對象,這個對象實際在默認狀況下是一個ExecutorCallbackCall對象,ExecutorCallbackCall對象內部包裹了一個OkHttpCall對象。

OkHttpCall

OkHttpCall對象是實際上執行網絡請求的類,這個對象實際是包裝了OkHttp裏面的Call對象。最終在enqueue等方法中會調用OkHttp的對應的方法。

小結

陸陸續續看了一段時間的retrofit源碼,雖然這個庫的代碼很少,可是設計思路很是的牛逼。咱們應該多吸取這種優秀三方庫的思想到咱們本身的代碼中

相關文章
相關標籤/搜索