retrofit源碼解析

在Android客戶端的項目網(wǎng)絡(luò)請求實踐中,對retrofit進行了實踐和源碼的閱讀。從retrofit的用法入手,對retrofit進行解析。
首先看一下retrofit的基本用法:
第一步創(chuàng)建retrofit對象:

Retrofit retrofit = new Retrofit.Builder()
          .baseUrl(baseUrl)
          .build();

第二步創(chuàng)建一個service接口,接口的組成如下

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

第三進行網(wǎng)絡(luò)請求

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

查看Retrofit的類結(jié)構(gòu),使用了經(jīng)典的Builder設(shè)計模式,通過Builder的方法我們通??梢栽O(shè)置OkHttpClient、HttpUrl、ConverterFactory、CallAdapterFactory等。
查看Retrofit的create方法

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的動態(tài)代理模式,關(guān)于代理模式和動態(tài)代理,可以查看這里
在create中,創(chuàng)建了一個最終暴露給我們的代理類A,類型為T,也就是xxService,內(nèi)部的委托類B為service,也是我們的類xxService。其中起到2個類的橋接作用的是一個實現(xiàn)了InvocationHandler接口的匿名類C,C為A的委托類,為B的代理類。最終A在外部對接口方法的調(diào)用會傳遞到C中,C再將調(diào)用傳遞給B。
在匿名類中

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

這一段代碼就是在代理類中進行的調(diào)用。我們進入這幾個方法可以看到retrofit對于xxService的整個處理。
查看loadService的代碼

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對象已經(jīng)存在就會使用已經(jīng)存在的緩存對象,避免每次對象在代理類里面運行的開銷。
進入ServiceMethod的build方法,我們可以看到retrofit對service的處理。我將service接口的處理過程梳理了一下

  1. 創(chuàng)建CallAdapter
  2. 創(chuàng)建處理返回數(shù)據(jù)格式的Converter
  3. 解析方法上方的注解。例如@FormUrlEncoded、@Post
  4. 新建參數(shù)處理對象ParamterHandler
  5. 對service接口中的方法參數(shù)進行讀取和解析,在這里,會對參數(shù)注解進行解析。

接下來我們對每一個步驟進行解析

CallAdapter

service的build中會調(diào)用retrofit的callAdapter方法,繼而調(diào)用nextCallAdapter方法。

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,并且根據(jù)returntype去除CallAdapter,結(jié)合動態(tài)代理部分可以看出,retrofit會把Call根據(jù)我們的CallAdapter轉(zhuǎn)換為想要的類型。例如retrofit+rxjava使用的時候把Call轉(zhuǎn)化為一個Observable。

Converter

接下來會執(zhí)行createResponseConverter方法,這個主要是解析返回的數(shù)據(jù)。在里面會調(diào)用retrofit的responseBodyConverter方法,類似callAdapter,接下來會調(diào)用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數(shù)據(jù)利用Gson解析為對應(yīng)的實體類對象。
而且在retrofit的Build類的build方法中,在存adapter的list里面加入了默認(rèn)的對象

adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

默認(rèn)添加的是一個DefaultCallAdapterFactory對象
而converter的list則會默認(rèn)添加一個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);
 }

其中最后一個參數(shù)的true和false是methodService中的hasBody變量
根據(jù)源碼我們可以將方法注解分類如下:

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

ParameterHandler

創(chuàng)建ParamterHandler對象,這個對象是用來處理參數(shù)的。在后面的request構(gòu)建會使用到。其中,每一個method的注解都有它對應(yīng)的ParamterHandler對象。

parseParameter

在serviceMethod對象build前的最后一步是解析method的參數(shù)注解,會將讀取到的數(shù)據(jù)傳入ParamterHandler對象中,最終拼成http請求的參數(shù)

最后,在Retrofit的create中,我們會返回一個Call對象,這個對象實際在默認(rèn)情況下是一個ExecutorCallbackCall對象,ExecutorCallbackCall對象內(nèi)部包裹了一個OkHttpCall對象。

OkHttpCall

OkHttpCall對象是實際上執(zhí)行網(wǎng)絡(luò)請求的類,這個對象實際是包裝了OkHttp里面的Call對象。最終在enqueue等方法中會調(diào)用OkHttp的對應(yīng)的方法。

小結(jié)

陸陸續(xù)續(xù)看了一段時間的retrofit源碼,雖然這個庫的代碼不多,但是設(shè)計思路非常的牛逼。我們應(yīng)該多吸收這種優(yōu)秀三方庫的思想到我們自己的代碼中

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容