Retrofit源碼詳細解析

該篇直接介紹Retrofit的原理,如果你還不是很熟悉retrofit的使用,可以看筆者對retrofit之前寫過的詳細介紹查看傳送門

1.Retrofit中的create()方法分析

通過Reftrofit.create(Class)方法,創建出Service inteface的實例,從而使得Service中配置的方法變的可用,即這是Retrofit的代碼結構的核心

  public <T> T create(final Class<T> 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 {
            //....
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

通過以上代碼核心方法,可以看到實例是通過Proxy.newProxyInstance()創建的,這個方法會爲參數中的多個interface創建一個對象,這個對象實現了interface中定義的所有方法,並且每個方法的實現雷同,調用對象實例內部的一個InvocationHandler成員變量的invoke()方法,並把自己的方法信息傳遞進去,這樣就在實質上實現了代理邏輯。並且這些方法的具體實現是在運行時生產interface實例時才確定。

  • loadServiceMethod()該方法負責讀取interface中原方法的信息,(包括返回值類型,方法註解,參數類型,參數註解),並將這些信息初步分析及校驗
   ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
  • 那麼可以分析loadServiceMethod(method)做了什麼事?根據method參數,構造一個ServiceMethod對象,那麼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;
  }

2. 接下來再看看ServiceMethod中是什麼東西?爲什麼將處理的方法都封裝爲ServiceMethod

  • 以下是源碼:
final class ServiceMethod<R, T> {
  
  final okhttp3.Call.Factory callFactory;
  final CallAdapter<R, T> callAdapter;

  private final HttpUrl baseUrl;
  private final Converter<ResponseBody, R> responseConverter;
  ...

  ServiceMethod(Builder<R, T> builder) {
    this.callFactory = builder.retrofit.callFactory();
    this.callAdapter = builder.callAdapter;
    this.baseUrl = builder.retrofit.baseUrl();
    this.responseConverter = builder.responseConverter;
    this.httpMethod = builder.httpMethod;
    this.relativeUrl = builder.relativeUrl;
    this.headers = builder.headers;
    this.contentType = builder.contentType;
    this.hasBody = builder.hasBody;
    this.isFormEncoded = builder.isFormEncoded;
    this.isMultipart = builder.isMultipart;
    this.parameterHandlers = builder.parameterHandlers;
  }
  //...
}
  • ServiceMethod中大致有以下成員變量及說明:

  • CallAdapter //這裏會根據平臺信息,返回Default或者說自定義的,比如RxJava2CallAdapter,默認實現的一個CallAdapter則實現了android線程的切換,通過Handler將線程切回到主線程。即Android

  • Converter //如GsonConvertAdapter,將okhttp的response轉爲json的處理adapter

  • Okhhtp3.Call.Factory 即配置的OkhttpClient

  • method //方法名

  • Annotation[] methodAnnotations //方法註解

  • Annotation[][] parameterAnnotationsArray //方法參數

  • ServiceMethod中保存了Http請求的所有的參數和當前方法需要調度的Call和Convert
    方法

  • 使用Map將method於ServiceMethod用於緩存,提高全局訪問的性能

3.開始創建OKHttpCall

OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);

當封裝完method轉化爲ServiceMethod後,執行上面這句,則創建出OkhttpCall對象,即將ServiceMehod中封裝的信息和參數,準備好這些資源以後,則全部交個OkhttpCall,從 OkHttpCall 這個名字來看就能猜到,它是對 OkHttp3.Call 的組合包裝,事實上,它也確實是。(OkHttpCall中有一個成員okhttp3.Call rawCall)。當然跟進去發現瞭如下代碼,是不是很熟悉?,顯然這是okhttp請求網絡的流程的真正開始的地方。可以看筆者之前對okhttp源碼分析的一系列文章傳送門

    Request request = serviceMethod.toRequest(args);
    okhttp3.Call call = serviceMethod.callFactory.newCall(request);

封裝爲Okhttp所需要的request對象,然後newCall創建一個

RealCall.newRealCall(this, request, false /* for web socket */);

則開始執行一個okhttp請求方法,至於okhttp如何網絡請求,這裏請參看筆者之前寫的okhttp的源碼的分析,這裏不做過多的研究,

4.執行CallAdapter

當執行Call.enqueue()方法後,或者說如果結合Rxjava進行訂閱了以後,則調用Okhttp的enqueue()方法,通過createCall()方法,得到OkhttpClient中返回的Response,然後根據之前在ServiceMethod中封裝的ConverAdapter方法,將Response進行

 response = parseResponse(rawResponse);

parseResponse核心方法

T body = serviceMethod.toResponse(catchingBody);

5. 執行convertAdapter

responseConverter.convert(body)

因爲在初始化Retrofit的時候設置了ConverterFactory爲

Retrofit.create(ApiService.class)
...
.addConverterFactory(GsonConverterFactory.create())
...

則使用GsonConverterFactory處理catchingBody,這裏在看看GsonConverterFactory的方法

final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
  private final Gson gson;
  private final TypeAdapter<T> adapter;

  GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
    this.gson = gson;
    this.adapter = adapter;
  }

  @Override public T convert(ResponseBody value) throws IOException {
    JsonReader jsonReader = gson.newJsonReader(value.charStream());
    try {
      return adapter.read(jsonReader);
    } finally {
      value.close();
    }
  }
}

到這裏,retrofit的請求網絡的大體流程則完成。

總結

Retrofit 使用了動態代理給將我們定義的接口設置了代理,當調用接口的方法時,Retrofit 會攔截下來,然後經過一系列處理,其實可以參考如下代碼,動態代理做的事情如下:

public interface Github{
	@GET("user/get")
	Call<List<User>> getUser();
	
	@GET("user/getUserInfo")
	Call<User> getUserInfo();
}

public class RealService implements Github{

	InvocationHandler invocationHandler = new InvocationHandler(){
		@Override
		public Object invock(Object proxy ,Method method,@Nullable Object[] args){
			//扮演代理身份,對不同的方法不同的處理
		}
	}

	@Override
	public Call<List<User>> getUser(){
		try{
		Method method = Github.class.getMethod("getUser");
		return invocationHandler.invock(this,method,null);
		}catch(Exception e){
			e.printStackTrace();
		}
	}
}

比如解析方法的註解和參數,生成了 Call 、Request 、等OKHttp所需的資源,最後交給 OkHttp 去發送請求, 此間經過 callAdapter,convertr 的處理。

在callAdapter處理的過程中,會將okhttp中的call,轉化爲Observable(自定義設定的,即使沒有,也會根據平臺創建一個默認的),最終執行call.execute(),開始真正的請求

將請求得到的結果通過convertAdapter處理後,轉化爲定義的返回類型,然後根據處理結果進行回調

即:Retrofit 中的數據其實是交給了 callAdapter 以及 converter 去處理,callAdapter 負責把 okHttpCall 轉成我們所需的 Observable類型,converter負責把服務器返回的數據轉成具體的實體類。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章