Retrofit2 源碼分析

將一個Java接口翻譯成一個Http請求,然后用OkHttp去發送這個請求

一 入口類 Retrofit ? 成員變量

private final ?HttpUrl baseUrl;//網絡請求基地址

private final List<Converter.Factory>converterFactories;//數據轉換器工廠集合

private final List<CallAdapter.Factory>?adapterFactories;//網絡請求適配器工廠集合

private final okhttp3.Call.Factory?callFactory;//底層進行網絡請求工廠

private final Executor?callbackExecutor;//回調方法執行器

/ServiceMethod是對業務接口中方法的注解進行解析之后得到的對象,該對象包含了訪問網絡的除了方法參數值之外的所有必要信息;如數據轉換器、網絡請求適配器、網絡請求工廠、基地址、Http方法等等。

private final Map<Method,ServiceMethod>?serviceMethodCache?=newLinkedHashMap<>();

Retrofit.bulid()方法 初始化 外觀模式

二 動態代理

https://www.ibm.com/developerworks/cn/java/j-lo-proxy1/ 動態代理的機制

http://www.ibm.com/developerworks/cn/java/j-jtp08305.html 動態代理的Decorator

GitHubServiceservice = retrofit.create(GitHubService.class);

create方法就是返回了一個Proxy.newProxyInstance動態代理對象

動態代理是java中的字節碼生成技術。通過接口生成代理類,并將代理類的實現交給InvocationHandler作為具體的實現 ,

動態代理作為 Decorator?

就是你要調用某個class方法的前后 ,你可以很方便的插入些你想要執行的額外代碼

一個動態代理類可以充當所有接口的 Decorator 或 Proxy,這樣就不用每個接口都編寫一個具體的實現類

Call <List<Repo>> repos = service.listRepos("octocat");

執行流程:

service對象其實是一個動態代理對象,并不是一個真正的GitHubService接口的implements產生的對象,當api對象調用listRepos方法時會被動態代理攔截,然后調用Proxy.newProxyInstance方法中的InvocationHandler對象的invoke方法。

invoke方法會傳入3個參數:

Object proxy, 代理對象

Method method,調用的方法 listRepos

Object... args 方法參數 octocat

Retrofit里的動態代理比較巧妙。它不關心proxyd,只是單純的為了拿到了這個method上所有的注解 生成ServiceMethod對象,生成的ServiceMethod對象和args構造生成了HttpCall ?可以發起HTTP請求的類

總結:簡化復雜的網絡請求,通過動態代理的去處理解析與拼裝HTTP請求


三 核心類 ServiceMethod

一個ServiceMethod對象對應于一個 API interface 的一個方法

主要成員變量

final okhttp3.Call.Factory callFactory; //負責創建 HTTP 請求

final CallAdapter callAdapter; //請求適配器? 把retrofit2.Call<T>轉為T

private final Converter responseConverter;? 負責把服務器返回的數據(JSON、XML、二進制或者其他格式,由ResponseBody封裝)轉化為T類型的對象

private final Headers headers; //請求頭信息

private final ParameterHandler[ ] parameterHandlers;//負責解析 API 定義時每個方法的參數,并在構造 HTTP 請求時設置參數

初始化過程 build()方法

callAdapter= createCallAdapter();//將遍歷一個CallAdapter.Factory列表,根據方法返回值類型和注解提供需要的網絡請求適配器

responseType=callAdapter.responseType();

responseConverter= createResponseConverter();//;即根據方法返回值類型和注釋從retrofit中獲取對應的轉換器

for(Annotation annotation :methodAnnotations) {

parseMethodAnnotation(annotation);//解析Method的注解 給ServiceMethod的成員變量賦值

}

for(intp =0;p < parameterCount;p++) {

...

parameterHandlers[p] = parseParameter(p,parameterType,parameterAnnotations);

//方法中的每個參數創建一個ParameterHandler對象,該對象的創建過程就對方法參數中的Body、PartMap、Part、FieldMap、Field等注解進行解析

}

核心:okhttp3.Call.Factory,CallAdapter.Factory和Converter.Factory三個工廠類,模塊之間、類之間通過接口進行依賴,創建十么樣的實現類交給工廠去處理,工廠同樣也是接口,添加怎樣的工廠,則在最初構造Retrofit對象時決定,各個模塊之間完全解耦,每個模塊只負責自己的責任

四 執行HTTP請求

4.1 OkHttpCall類中execute() 同步發起網絡請求,執行分析

createRawCall() ? ?

1調用了serviceMethod.toRequest(args)來創建okhttp3.Request對象,之前解析參數注解的parameterHandlers在這里給HTTP請求 設置參數傳進入,最后RequestBuilder build()生成Request請求

2 再調用serviceMethod.callFactory.newCall(request)來創建okhttp3.Call,這里之前準備好的callFactory同樣也派上了用場,由于工廠在構造Retrofit對象時可以指定,所以我們也可以指定其他的工廠,來使用其它的底層 HttpClient 實現。這里Retrofit2就和Okhttp結合起來了 網絡請求的執行業務流程都交給Okhttp來處理

return parseResponse(call.execute());

調用okhttp3.Call#execute()來執行網絡請求,這個方法是阻塞的,執行完畢之后將返回收到的響應數據。收到響應數據之后,進行狀態碼的檢查,再調用serviceMethod.toResponse(catchingBody)來把響應數據轉化成我們需要的數據類型對象。使用之前準備好的responseConverte轉化數據。

4.2 enqueue(Callback callback) 異步執行

這里的異步交給了okhttp3.Call#enqueue(Callback responseCallback)來實現,并在它的 callback 中調用parseResponse解析響應數據,并轉發給傳入的 callback

五 ?CallAdapter 接口

請求的適配化OkHttpCall --Adapter--> RxJava/java8/UICallback

通過適配器實現OkHttpCall到其它類型(比如RxJava等第三方庫)的適配轉換

public Interface CallAdapter<T>?{

Type?responseType();//該請求適配器返回的數據類型

?T?adapt(Call call);//該請求適配器對原始Call的再次封裝,如Call到Observable,

abstract class ?Factory?{

public abstract CallAdapter?get(Type?returnType,?Annotation[]?annotations,?Retrofit?retrofit);//獲取網絡請求適配器

protected ? ?staticType?getParameterUpperBound(intindex,?ParameterizedType?type)?

{returnUtils.getParameterUpperBound(index,?type);?}

protectedstaticClass?getRawType(Type?type)?{returnUtils.getRawType(type); }

}

ExecutorCallAdapterFactory 是Retrofit默認實現 ?

該對象存儲一個回調執行器,異步請求將相應的結果交給callbackExecutor回調執行器去執行Android平臺Retrofit2會使用主線程handler構造一個ExecutorCallAdapterFactory,調用enqueue(Callback),callback回調會在主線程中回調

5.1 Retrofit2和RxJava的結合使用

1 RxJavaCallAdapterFactory類?

?RxJava對請求進行包裝,它將根據網絡請求生成一個Observable進行流式任務執行

getCallAdapter方法中對返回值的泛型類型進行了進一步檢查,例如我們聲明的返回值類型為Observable,泛型類型就是List,這里對retrofit2.Response和retrofit2.adapter.rxjava.Result進行了特殊處理,有單獨的 adapter 負責進行轉換,其他所有類型都由SimpleCallAdapter負責轉換

2 SimpleCallAdapter#adapt方法

創建了一個Observable,傳入了CallOnSubscribe類,同時使用了一個OperatorMapResponseToBodyOrError操作符,用來把retrofit2.Response轉為我們聲明的類型,或者錯誤異常類型

3 CallOnSubscribe#call方法

clone 了原來的 call,因為okhttp3.Call是只能用一次的,所以每次都是新 clone 一個進行網絡請求;創建了一個叫RequestArbiter的 producer,把這個 producer 設置給 subscriber;

Producer機制 簡單的理解

Subscriber 都是被動接收 Observable 傳遞 過來的數據,然后Subscriber做處理。

但要是 Observable 發得太多,Subscriber 處理不過來,那就有問題了,所以就有了一種 Subscriber 主動 pull 的機制,而這種機制就是通過 Producer 實現的。給 Subscriber 設置 Producer 之后(通過Subscriber#setProducer方法),Subscriber 就會通過 Producer 向上游根據自己的能力請求數據(通過Producer#request方法),而 Observable 收到請求之后再根據請求的量給 Subscriber 發數據。

RequestArbiter#request方法

執行call.execute() 獲取到Response響應數據,并且發送給下游接收

Observable.lift(OperatorMapResponseToBodyOrError.instance())

lift操作符 負責接收原始的Observable發出的事件,并在response.body()并發送給下游。這里,body()返回的就是我們聲明的泛型類型了

Call<R>->Response<T>->Observable<T> ?執行流程

1 Observable.subscribe,觸發 API 調用的執行;

2 CallOnSubscribe#call,clone call,創建并設置 producer;

3 subscriber 被設置了 producer 之后調用RequestArbiter#request,在 request 中發起網絡請求,把處理結果發給下游;

4 OperatorMapResponseToBodyOrError$1#onNext,把 response 的 ?body 發給下游

5 最終就到了我們 subscribe 時傳入的回調里面了;

六? ? 概括Retrofit2的話,借鑒了服務器編程中AOP思想,利用動態代理技術通過接口在運行時攔截方法,接著通過解析注解拼裝HTTP請求;最后包裝了OkHttpCall生成真正的請求類 發起網絡請求, 通過抽象工廠讓各個模塊直接解耦,完成對原數據Respone的Conver,實現了對Rx、線程的Adapter ,

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

推薦閱讀更多精彩內容