在使用了Retrofit以後,你是否會有這樣的疑問:html
一、爲何有OkHttp這麼強大的網絡框架了,Retrofit還能脫穎而出?
二、Retrofit是怎麼適配第三方框架的?
三、Retrofit用了哪些設計模式?
四、Retrofit爲何好用?java
下面咱們就來探索Retrofit的真面目吧!react
本文基於如下Java版本解析:android
// retrofit
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.retrofit2:converter-gson:2.0.2'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
// rxjava
implementation 'io.reactivex.rxjava2:rxjava:2.1.6'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
複製代碼
本文目錄:git
Retrofit不是一個純網絡框架,爲何這麼說呢? Retrofit是基於OkHttp框架來實現請求的,而Retrofit是基於OkHttp框架實現的一套封裝,利用動態代理實現了簡單的網絡請求實現,並支持Gson,RxJava等第三方框架的適配,簡而言之,就是讓你的網絡請求更便捷,更強大了;github
那麼Retrofit底層究竟是怎麼封裝的呢? 是怎麼變得更便捷,更強大了呢?編程
接下來讓咱們來深刻源碼,一探究竟!json
光說源碼,不講使用,總感受有點被架空,容易找不到點;設計模式
那麼接下來咱們先來看一下Retrofit的簡單使用吧;api
Retrofit接口:
public interface GetRequestInterface {
@GET("openapi.do?keyfrom=Yanzhikai&key=2032414398&type=data&doctype=json&version=1.1&q=car")
Call<ResultData> getCall();
@GET("openapi.do?keyfrom=Yanzhikai&key=2032414398&type=data&doctype=json&version=1.1&q=car")
Observable<ResultData> getObservableCall();
@GET("openapi.do?keyfrom=Yanzhikai&key=2032414398&type=data&doctype=json&version=1.1&q=car")
Call<StudentBean> getItem(@Query("student") String student, @Query("type") String type);
}
複製代碼
基礎請求URL:
public class BaseRequest {
public static final String BaseURL = "https://fanyi.youdao.com/";
}
複製代碼
Retrofit的使用:
// Retrofit 實例的建立
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BaseRequest.BaseURL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
// 建立請求接口類
GetRequestInterface request = retrofit.create(GetRequestInterface.class);
// ---普通網絡請求---
// 獲取請求對象Call
Call<ResponseBody> call = request.getCall();
// 執行網絡請求
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
ResponseBody body = response.body();
Log.i("TAG", "MainActivity onResponse response:" + response.toString());
Log.i("TAG", "MainActivity onResponse body:" + (body == null ? "null" : body.toString()));
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.i("TAG", "MainActivity onFailure t:" + t.toString());
}
});
// ---RxJava網絡請求---
Observable<ResultData> observableCall = request.getObservableCall();
observableCall.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<ResultData>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(ResultData resultData) {
Log.i("TAG", "retrofit onNext resultData:" + resultData.toString());
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
Log.i("TAG", "retrofit onComplete ");
}
});
複製代碼
主要分爲幾步:
(1)經過構造者模式建立Retrofit實例;
(2)經過動態代理建立接口的實例;
(3)經過接口的實例獲取到網絡請求的操做類Call;
(4)經過Call來執行網絡請求;
看一下大體流程圖:
下面咱們基於使用來深刻框架,探索其源碼的精妙!
// Retrofit 實例的建立
Retrofit retrofit = new Retrofit.Builder()
// 建立baseUrl
.baseUrl(BaseRequest.BaseURL)
// 添加GsonConverterFactory
.addConverterFactory(GsonConverterFactory.create())
// 添加RxJava的RxJavaCallAdapterFactory
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
// 構建Retrofit的實例
.build();
複製代碼
Retrofit的構建使用了建造者模式,這個模式的優勢就是能夠構造複雜的對象,方便擴展,而且看起來代碼比較簡潔,美觀;
在開始以前,咱們先來看一下Retrofit的成員變量;
這裏的變量並非不少,咱們來一個個分析;
**(1)Map<Method, ServiceMethod<?>> serviceMethodCache:**這是一個方法的緩存類,key爲網絡請求的Method,好比GET,POST等,而ServiceMethod則對應着動態代理解析後的方法類;
**(2)okhttp3.Call.Factory callFactory:**這個是建立OkHttp的工廠類;
**(3)HttpUrl baseUrl:**這個是基礎URL,網絡請求會帶上這個基礎URL;
**(4)List<Converter.Factory> converterFactories:**Converter.Factory的集合,Converter.Factory是將返回的數據經過這個工廠轉化爲對應的數據,好比Gson的GsonConverterFactory工廠類,也就是數據轉化器工廠;
**(5)List<CallAdapter.Factory> callAdapterFactories:**CallAdapter.Factory的集合,CallAdapter.Factory是網絡請求的適配器工廠,好比把Call轉化爲RxJava請求的RxJavaCallAdapterFactory工廠,也就是Call轉化工廠;
**(6)Executor callbackExecutor:**用於回調網絡請求;
**(7)boolean validateEagerly:**用於判斷是否須要當即解析方法,這個咱們在將動態代理的時候會講到;
咱們看完了Retrofit的成員變量,可是Retrofit的建立是經過Builder來建立的,下面咱們來看看Retrofit的Builder的變量有哪些,分別有哪些做用;
從圖片能夠看出,和Retrofit的變量差很少,惟一有區分的就是多了Platform和validateEagerly變量,讓咱們經過源碼來看看這兩個是作什麼的;
先來看一下這個Platform的賦值;
這個Platform是經過Platform.get()方法獲取的,來看看這個方法是啥邏輯;
從圖片能夠看出,最終是調用的findPlatform()方法;
這個方法會返回Android,Java,Platform等類,主要是用來判斷對於的平臺,而後獲取到對於的Platform;
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
// 判斷從系統中獲取到的SDK不爲0的時候,則爲Android平臺;
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
try {
Class.forName("java.util.Optional");
// 若是不是Android平臺的話,那麼就返回Java的平臺;
return new Java8();
} catch (ClassNotFoundException ignored) {
}
// 默認的返回值;
return new Platform();
}
複製代碼
而Build.VERSION.SDK_INT的判斷邏輯爲:
翻譯過來的意思就是:
當前在此硬件上運行的軟件的SDK版本。這個值在設備啓動時不會改變,但可能會在硬件製造商提供OTA更新時改變;
下面咱們來看一下這個Android類對應的源碼:
Android類對應的源碼很少,就幾個方法,這裏咱們重點關注下面這幾個方法:
**(1)defaultCallbackExecutor():**默認的線程執行器Executor,從源碼能夠看出,獲取的是主線程的Hander,execute的時候,會post到主線程執行;
**(2)defaultCallAdapterFactories:**獲取默認的CallAdapter.Factory,用於建立CallAdapter;
**(3)defaultConverterFactories:**獲取默認的數據轉換工廠ConverterFactory,用於建立轉換器Converter;
總結:Platform主要是用於適配不一樣的平臺,用於獲取默認的Executor,請求適配器工廠類CallAdapterFactory,數據轉換工廠類ConverterFactory等;
baseUrl,是咱們網絡請求的基礎URL;
咱們進源碼裏面看一下,具體作了啥操做;
這裏主要作了兩步操做:
一、首先第一步是經過解析這個baseUrl並返回一個HttpUrl對象; 二、第二步是將第一步建立的HttpUrl對象賦值給Builder;
這裏咱們主要看第一步的具體操做,這裏的邏輯是在HttpUrl的 parse(@Nullable HttpUrl base, String input)裏,經過解析URL,判斷該請求的scheme是爲http仍是https,若是不是這其中一個,那麼就會拋出異常,源碼咱們大體看一下;
而後下面還會解析URL,獲取到主機地址host,端口號port,具體源碼我就不貼了,感興趣的能夠跟着源碼看一下;
這個咱們上面在接受Retrofit的成員變量的時候有提過,是用於建立Converter的工廠,使用了抽象工廠的設計模式,而Converter是用來將請求返回的數據,轉化爲對應平臺的數據,而這裏,咱們使用的是Gson平臺;
咱們先來看一下這個Converter.Factory,看看其背後是怎麼實現的;
從源碼能夠看出,Converter.Factory是Converter的內部類,主要有兩個方法,一個是requestBodyConverter,用於將請求的RequestBody轉換爲對應的轉換器Converter;
另外一個方法是responseBodyConverter,用於將返回的返回體ResponseBody轉換爲對應的轉換器Converter;
而轉換器Converter裏面只有一個方法convert,用於將返回的數據轉換爲對應的類型;
咱們在建立Retrofit的實例時,是經過GsonConverterFactory.create()來建立對應的轉換器工廠的,下面咱們來看看這個Gson的轉換器工廠是怎麼實現的;
先來看一下這個create()的方法;
最終是走的這裏,進行了簡單的賦值;
GsonConverterFactory這個工廠最重要的仍是responseBodyConverter和requestBodyConverter方法,下面咱們來具體分析;
在requestBodyConverter方法裏面,經過class的Type類型,建立了Gson的TypeAdapter,這個TypeAdapter很熟悉,就是咱們使用gson解析會用到的類,最終經過TypeAdapter和gson的參數建立了GsonRequestBodyConverter對象,下面來瞄一眼這個類的代碼;
這個類的源碼很簡單,咱們主要convert()這個方法;
這個方法的邏輯就是將傳進來的value值經過TypeAdapter將其轉化爲ByteString,而後再傳進RequestBody做爲參數來構建RequestBody對象;
這個方法咱們先了解到這裏,後面在這個requestBodyConverter調用的地方再來說一下;
這個方法和上面那個requestBodyConverter方法有點相似,也是經過class的Type類型,建立了Gson的TypeAdapter,最終經過TypeAdapter和gson的參數建立了GsonResponseBodyConverter,同理,咱們也來看一下這個類的實現吧;
源碼很簡單,這裏咱們也是關注convert()這個方法;
這裏的邏輯有沒有很熟悉,就是咱們常常用的gson解析,經過TypeAdapter讀取JsonReader的數據,返回對應的數據類型,這裏的參數ResponseBody就是咱們上面GsonRequestBodyConverter的convert方法生成的;
到這裏GsonConverterFactory就講的差很少了,後面咱們在用到的地方再詳細講一下;
CallAdapter.Factory,從命名能夠看出,是用來建立CallAdapter的工廠類,使用了抽象工廠的設計模式,而CallAdapter是用於將Call轉化爲咱們所須要的請求類型,好比將Call轉化爲RxJava的調用類型;
而CallAdapter裏面是經過adapt方法來進行轉換的,adapt是接口的一個方法,交給子類去實現,這個方法的邏輯,咱們下面將Retrofit的解析時,再統一講解,這裏是須要瞭解這是一個轉換的方法便可;
下面咱們來看看建立CallAdapter的工廠裏面都有哪些方法,分別是用來幹嗎的;
這個Factory的邏輯不多,只有幾個方法,這裏咱們主要關注get方法,經過get方法來獲取CallAdapter的對象,同理,這裏也是交給子類去實現;
而上面咱們Retrifit的建立,在CallAdapter.Factory的添加時,使用了RxJava的工廠,也就是RxJava2CallAdapterFactory,用於將Call請求轉換爲RxJava對應的請求;
下面咱們來看看這個RxJava2CallAdapterFactory的實現邏輯吧;
RxJava2CallAdapterFactory的建立,也是經過RxJava2CallAdapterFactory.create()的方法,那麼咱們來看下這個create方法作了啥?
只是簡單的new了一個RxJava2CallAdapterFactory,而構造方法裏也沒有其餘的邏輯了,只是對Scheduler進行賦值,而這裏建立時,傳的是null;
上面咱們看完RxJava2CallAdapterFactory的建立後,下面咱們來看一下RxJava2CallAdapterFactory是怎麼經過get方法建立一個CallAdapter的;
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
Class<?> rawType = getRawType(returnType);
if (rawType == Completable.class) {
// 建立RxJava2CallAdapter
return new RxJava2CallAdapter(Void.class, scheduler, isAsync, false, true, false, false,
false, true);
}
...
// 建立RxJava2CallAdapter
return new RxJava2CallAdapter(responseType, scheduler, isAsync, isResult, isBody, isFlowable,
isSingle, isMaybe, false);
}
複製代碼
這個方法職責很明確,就是根據各類參數來建立RxJava的CallAdpter,也就是RxJava2CallAdapter;
這裏咱們來重點關注一個RxJava2CallAdapte的adapt方法的邏輯;
public Object adapt(Call<R> call) {
// 第一步:根據是不是異步的參數建立對應的Observable
Observable<Response<R>> responseObservable = isAsync
? new CallEnqueueObservable<>(call)
: new CallExecuteObservable<>(call);
Observable<?> observable;
// 第二步:根據各類判斷,再封裝一層Observable返回
if (isResult) {
observable = new ResultObservable<>(responseObservable);
} else if (isBody) {
observable = new BodyObservable<>(responseObservable);
} else {
observable = responseObservable;
}
...
return observable;
}
複製代碼
這個方法的邏輯並複雜,主要是將Call請求轉化爲RxJava的請求,最終返回一個RxJava的被觀察者:Observable,用於進行RxJava類型的網絡請求,如上面的示例;
這個方法的邏輯主要有兩步,咱們先來看一下第一步建立的被觀察者,這裏會先判斷是不是異步,若是是異步的話,那麼就建立CallEnqueueObservable,不然就建立CallExecuteObservable;
這兩個的區別就是,在調用訂閱(subscribe)的時候,會執行CallEnqueueObservable的subscribeActual方法,最終是經過OkHttpCall的enqueue方法來執行異步請求;
而CallExecuteObservable在調用訂閱(subscribe)的時候,也會執行CallEnqueueObservable的subscribeActual方法,在這個方法裏,就直接調用OkHttpCall的execute方法來執行同步請求;
而第二步的封裝,這裏咱們主要以BodyObservable來進行講解,這個類會對訂閱的觀察者進行封裝,在onNext方法中將body返回;這一步能夠理解爲對返回的結果進行處理;
這裏是RxJava的用法,我默認你是會的,若是對RxJava還不熟悉的同窗,能夠後面去看看RxJava的用法;
到此,Retrofit的CallAdapter.Factory的邏輯就先告一段落了,下面咱們來看看Retrofit的最終build()方法的邏輯;
廢話很少說,咱們直接擼源碼;
public Retrofit build() {
// 判斷當callFactory(OkHttpClient)爲空,就從新建立一個OkHttpClient進行賦值;
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
// 判斷Executor爲空時,就用Platform的默認Executor進行賦值,上面咱們講過,這裏面使用的是主線的的Handler;
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// 經過添加的CallAdapter.Factory來建立一個新的CallAdapter.Factory集合;
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
// 添加Platform的默認CallAdapter.Factory,若是咱們沒有添加CallAdapter.Factory,那麼就會使用這個Platform的默認CallAdapter.Factory; callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
// 建立Converter.Factory的集合
List<Converter.Factory> converterFactories = new ArrayList<>(
1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
// Add the built-in converter factory first. This prevents overriding its behavior but also
// ensures correct behavior when using converters that consume all types.
// 添加默認的Converter.Factory
converterFactories.add(new BuiltInConverters());
// 添加自定的Converter.Factory
converterFactories.addAll(this.converterFactories);
// 添加Platform的默認Converter.Factory
converterFactories.addAll(platform.defaultConverterFactories());
// 最終建立Retrofit實例;
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
複製代碼
這個build()方法,主要是作各類參數的賦值,最終經過參數來建立Retrofit的實例,那麼到這裏Retrofit的建立就差很少將完了,下面咱們將會學習到Retrofit的核心;
爲何咱們能夠經過接口定義一個類型,就能夠執行請求了,對於這些方法的解析,以及參數的賦值的操做是在哪裏呢?
這麼就涉及到Retrofit使用的一個很重要的設計模式了,也就是動態代理設計模式;
舉個例子,假如我要去超市買水果,但是我好懶,週末就想呆在家裏不想出門,可是內心又很想吃水果,那怎麼辦呢?
只能打開外賣App,在上面買完以後,由外賣小哥送過來,這時候,我就經過中介,外賣App來買到水果,而這個過程叫作代理;
不直接操做,而是委託第三方來進行操做,從而達到目的;
而Java的代理分爲靜態代理和動態代理;
若是代理類在程序運行以前就已經存在了,那麼這種代理方式就被稱爲靜態代理;
仍是以上面的例子,我要買水果,來定義一個買水果的接口Operator;
public interface Operator {
// 買水果
void buyFruit();
}
複製代碼
而咱們的代理類外賣App須要實現這個接口,同時,將須要委託的對象傳進來,在buyFruit的過程當中,作了一些出來,好比去超市取貨,取完貨以後,再送貨;
public class AppAgent implements Operator {
private Operator operator;
public AppAgent(Operator operator) {
this.operator = operator;
}
@Override
public void buyFruit() {
// 一、在App上,提供商品給用戶下單
// 二、根據訂單去超市採購水果
operator.buyFruit();
// 三、送貨給客戶
}
}
複製代碼
委託的對象,超市:
public class Market implements Operator {
@Override
public void buyFruit() {
// 到超市買水果
}
}
複製代碼
那麼最終的實現效果就是,咱們經過外賣App的一頓操做,從超市買到了水果,以下:
public class Main {
public static void main(String[] args) {
// 委託對象,超市;
Market market = new Market();
// 代理對象,外賣App;
AppAgent appAgent = new AppAgent(market);
// 經過外賣App的代理,從超市買到了水果;
appAgent.buyFruit();
}
}
複製代碼
以上就是咱們靜態代理的過程,這個例子只是舉了買水果這個過程,可是若是我還想要買菜,買生活用品等一系列東西呢?
我就得在接口Operator裏面再多新增好幾個方法,一樣的代理類也要跟着去重寫一堆的方法,可是這些方法作的操做其實都是同樣的,都是買這個動做,可是咱們不得已,新增一種類型,咱們就得在代理類裏面再重寫並調用;
那麼這個過程實際上是能夠抽出來的,這種方式就叫作動態代理;
動態代理,和靜態代理不一樣的是,動態代理的方法是運行後才建立的,而靜態代理是運行前就存在的了;
說白了,和靜態代理不一樣的是,動態代理的方法都是在運行後,自動生成的,因此叫動態代理;
下面咱們來看看動態代理是咋用的;
在使用動態代理的時候,被代理類須要實現InvocationHandler這個接口,,這個invoke方法是在動態生成的代理類中調用的,對應着咱們上面在靜態代理operator.buyFruit()這個方法的調用,下面來看一下這個方法對應的參數;
public interface InvocationHandler {
// Object proxy:接口的具體實現類;
// Method method:解析以後自動生成的方法;
// Object[] args:方法對於的參數;
Object invoke(Object proxy, Method method, Object[] args);
}
複製代碼
而最終運行時生成的代理類,通常名稱會是 Proxy1這種,經過Proxy.newProxyInstance()方法來生成的,這個下面會講到,先來看一下下面的僞代碼;
public final class $Proxy0 extends Proxy implements Operator {
public final boolean buyFruit() {
// h是InvocationHandlel,調用了invoke方法;
super.h.invoke(this, m1, (Object[])null);
}
}
}
複製代碼
在生成的代理類中,會實現咱們的接口,並重寫方法,在方法裏面經過InvocationHandler回調參數到invoke方法裏,最終經過反射調用被代理對象的方法;
而咱們經過實現這個InvocationHandler接口,在invoke方法裏面,經過method.invoke(object, args)能夠來調用被代理的方法,而後咱們能夠在這個method.invoke(object, args)以前或者以後作一些處理,這樣因此的方法均可以一併進行處理,而不是每次新增一個方法,就得重寫一遍邏輯;
下面來看一下具體實現:
public class CustomProxy implements InvocationHandler {
private Object object;
public CustomProxy(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 一、在App上,提供商品給用戶下單
// doSomeThing();
// 二、根據訂單去超市採購東西(在這個方法以前或者以後均可以統一處理操做)
Object invoke = method.invoke(object, args);
// 三、送貨給客戶
// doSomeThing();
return invoke;
}
}
複製代碼
下面來看一下,最終的調用;
public class Main {
public static void main(String[] args) {
// 建立被代理類
CustomProxy customProxy = new CustomProxy(new Market());
// 動態生成代理類
Operator proxyInstance = (Operator) Proxy.newProxyInstance(Operator.class.getClassLoader(), new Class[]{Operator.class}, customProxy);
// 調用對應的方法
proxyInstance.buyFruit();
}
}
複製代碼
這裏經過Proxy.newProxyInstance()方法,動態生成代理類$Proxy0這種,這裏涉及到的反射的知識,就再也不贅述了;
而後動態代理類調用方法,最終會走到CustomProxy的invoke()方法,而後咱們在這個方法裏面經過method.invoke(object, args)來進行最終的代理調用,而在這個最終的代理調用的先後,咱們能夠實現自定義的邏輯;
這個實現了InvocationHandler接口的CustomProxy,更像是一個攔截類,在代理方法的調用過程當中進行攔截,而後再實現咱們的自定義邏輯;
至此,動態代理你理解了嗎?沒有理解也不要緊,多看幾遍,多練幾遍就能夠了;
首先,讓咱們來想一個問題,Retrofit爲何要使用動態代理?
使用動態代理的好處就是在調用方法以前,咱們能夠統一作一些操做,而沒必要新增一個方法就去寫一遍邏輯;
而Retrofit巧妙的使用了動態代理在調用接口的方法以前,統一的去解析處理Header和URL等操做;
這樣就不用每次在新增一個請求的方法,就去寫一遍這個解析的邏輯;
那麼接下來咱們來看看Retrofit的怎麼解析這些接口的;
下面咱們來看一下Retrofit的create的方法,動態代理的邏輯是在這裏實現的;
public <T> T create(final Class<T> service) {
...
// 驗證接口的參數以及配置是否正確
if (validateEagerly) {
eagerlyValidateMethods(service);
}
// 動態代理
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {
// 判斷是不是Object,若是是的話,就直接調用方法返回
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
// 判斷是不是Java8平臺的默認方法類型,若是是的話,就調用Java8平臺的invokeDefaultMethod方法
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
// 解析方法;
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
複製代碼
這裏咱們將這個方法分爲兩步;
** 第一步:** eagerlyValidateMethods方法,這個方法的邏輯是用於加載接口的配置,用於判斷接口對應的header,body以及方法的參數等配置是否正確,若是不正確那麼就會拋出異常;
** 第二步:** loadServiceMethod方法,這個方法的邏輯主要是用於解析咱們在接口配置的註解以及參數,好比header,body,url等等;
這裏咱們重點關注第二步的loadServiceMethod方法方法;
咱們來看一下其源碼的具體實現;
ServiceMethod<?> loadServiceMethod(Method method) {
// 先從緩存map集合裏面獲取ServiceMethod;
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
// 若是從緩存map裏面獲取不到ServiceMethod,那麼再經過解析註解,獲取到ServiceMethod對象;
result = ServiceMethod.parseAnnotations(this, method);
// 將解析後的ServiceMethod對象存入到map集合中;
serviceMethodCache.put(method, result);
}
}
return result;
}
複製代碼
這裏作的操做很簡單,就是獲取ServiceMethod,而在獲取ServiceMethod的過程當中,會先從緩存的map中獲取,若是獲取不到了再進行解析,這樣就沒必要獲取一次ServiceMethod,就去解析一次,比較耗性能;
而這個ServiceMethod的類是個抽象類,只有兩個方法,一個是靜態的parseAnnotations方法,一個是抽象的invoke方法;
咱們先來看一下這個parseAnnotations方法;
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
// 經過解析接口方法的註解,獲取RequestFactory
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
...
// 解析註解並獲取ServiceMethod對象
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
複製代碼
這個方法的邏輯也不是很複雜,主要分爲兩步;
第一步: 獲取RequestFactory;
第二步: 獲取ServiceMethod;
咱們先來看第一步的操做;
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
複製代碼
經過Builder來建立RequestFactory,來看看這個Builder作了啥操做;
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
// 獲取方法全部的註解,包括本身聲明的以及繼承的
this.methodAnnotations = method.getAnnotations();
// 獲取方法參數的全部類型,包含泛型;
this.parameterTypes = method.getGenericParameterTypes();
// 獲取方法參數上的全部註解
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
複製代碼
這個方法的邏輯很簡單,就是作一些賦值操做,這裏須要注意的是這幾個反射的方法,下面的build方法會用到;
RequestFactory build() {
for (Annotation annotation : methodAnnotations) {
// 遍歷方法的註解,解析方法的參數配置,獲取到請求的url,header等參數
parseMethodAnnotation(annotation);
}
...
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
// 遍歷方法的參數,以及參數的類型,解析方法的參數邏輯
parameterHandlers[p] = parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p]);
}
...
// 根據上面解析的參數配置,建立RequestFactory
return new RequestFactory(this);
}
複製代碼
這個方法的邏輯就比較重要了,咱們在接口的方法裏面定義的相關url,header等註解,最終就是在這裏解析並轉化爲okhttp請求的Call,那麼咱們來看看這裏究竟是怎麼解析的;
先來看一下parseMethodAnnotation這個方法, 這個方法的主要邏輯是用於解析方法註解的配置信息;
下面咱們來看看這個類的具體實現;
這個方法的邏輯比較多,咱們大體看一下就能夠了,這裏面作的主要職責就是經過註解Annotation,獲取到url,header,isMultipart等參數,並將其賦值給建造者Builder的成員變量;
對於這個方法,這裏就很少說了,感興趣的跟着源碼去看一下;
而第二個方法parseParameter,也是遍歷上面獲取到的方法的參數類型parameterTypes以及方法參數的註解parameterAnnotationsArray,來解析並獲取相關配置,而這個方法最終是調的parseParameterAnnotation方法的邏輯;
主要是用於解析這裏的邏輯:
下面咱們來看看具體實現;
這個parseParameterAnnotation方法的邏輯和上面的parseMethodAnnotation方法有點相似,也是經過判斷對於的類型來進行解析,這裏源碼過長,就不貼出來了;
這裏咱們就找其中一個Query的解析來進行分析;
省略前面的代碼
...
else if (annotation instanceof Query) {
...
// 將註解annotation強轉爲Query
Query query = (Query) annotation;
// 獲取註解Query對應的值;
String name = query.value();
...
if (Iterable.class.isAssignableFrom(rawParameterType)) {
// 判斷這個參數的類型爲Class類型;
...
// 建立ParameterHandler的子類Query
return new ParameterHandler.Query<>(name, converter, encoded).iterable();
}
...
}
...
省略後面的代碼
複製代碼
這裏最終解析獲取的是ParameterHandler.Query類,這個類裏面有個apply的方法,會在接口請求的時候會調用到,目的是經過請求的RequestBuilder將解析出來的參數,添加到RequestBuilder裏去;
這裏咱們瞭解一下就能夠了;
這裏還有一個須要注意的點,就是這裏的解析,涉及到Converter這個convert方法的邏輯;
這裏我以Body爲例,在Body這個類的apply方法裏,會經過Converter這個convert方法,將body參數轉化爲對應類型的數據;
這個apply的方法是在進行網絡請求的時候會調用,具體調用鏈以下,這裏以RxJava爲例:
一、RxJavaCallAdapterFactory.ResponseCallAdapter的adapt方法;
二、RxJavaCallAdapterFactory.CallOnSubscribe的call方法;
三、RxJavaCallAdapterFactory.RequestArbiter的request方法;
四、OkHttpCall的execute方法;
五、OkHttpCall的createRawCall方法;
六、RequestFactory的create方法;
七、ParameterHandler的apply方法;
最終在這裏觸發了apply方法的調用,這裏源碼就不貼出來了,感興趣的朋友,能夠跟着源碼去看一遍;
咱們上面看的RequestFactory的build方法的最後一個,建立RequestFactory,這裏的邏輯就是將咱們上面解析出來的參數,給這個RequestFactory進行賦值;
那麼到這裏parseAnnotations的第一步就講完了,先來總結一下,這一步主要是解析方法註解和方法參數的註解,從而獲取到對應的參數配置,最終將其賦值給RequestFactory對象;
下面咱們來看HttpServiceMethod的parseAnnotations方法;
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations( Retrofit retrofit, Method method, RequestFactory requestFactory) {
// 建立CallAdapter
CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method);
...
// 建立Converter
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
// 經過參數建立HttpServiceMethod
okhttp3.Call.Factory callFactory = retrofit.callFactory;
return new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter);
}
複製代碼
這個方法的邏輯並不複雜,主要分三步:
第一步: 建立CallAdapter;
第二步: 建立Converter;
第三步: 經過參數建立HttpServiceMethod;
這裏主要關注的是前兩步,建立了CallAdapter和Converter;
咱們先來看一下第一步的邏輯;
這裏的調用鏈是這樣的,首先調用了HttpServiceMethod的createCallAdapter方法,而後再調用了Retrofit的callAdapter方法,最後調用了Retrofit的nextCallAdapter方法;
咱們來看看nextCallAdapter的邏輯;
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
...
// 經過callAdapterFactories的get方法來建立CallAdapter
int start = callAdapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
...
}
複製代碼
這裏的邏輯不復雜,最終經過CallAdapter.Factory來建立CallAdapter,而這個CallAdapter.Factory的邏輯咱們上面已經講過了,就是用來建立CallAdapter的工廠;
下面咱們來看第二步的調用;
第二步的調用鏈是這樣的,先調用HttpServiceMethod的createResponseConverter方法,而後再調用Retrofit的responseBodyConverter方法,最終調用了Retrofit的nextResponseBodyConverter方法,咱們來看看nextResponseBodyConverter這個方法的邏輯;
public <T> Converter<ResponseBody, T> nextResponseBodyConverter( @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
...
int start = converterFactories.indexOf(skipPast) + 1;
// 先經過Converter.Factory工廠建立Converter,再經過Converter來轉化返回的數據
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;
}
}
...
}
複製代碼
第二步的邏輯和第一步相似,最終經過Converter.Factory工廠的responseBodyConverter方法建立了Converter,而這個Converter.Factory的邏輯,我在上面也已經講過了;
而這個Converter獲取的是返回體的Converter,用於將返回的數據轉化爲對應的平臺的數據,好比Gson,而這裏的Converter的convert的方法,最終是在OkHttp的網絡請求成功以後調用的,具體調用鏈以下:
一、OkHttpCall的enqueue方法;
二、OkHttpCall的parseResponse方法; 三、Converter的convert方法;
調用鏈也不是很複雜,感興趣的朋友能夠跟着源碼去看一下,這裏就不貼源碼了;
那麼到這裏,HttpServiceMethod的parseAnnotations方法就已經講完了;
下面,咱們回到Retrofit的create這個方法,在調用完loadServiceMethod方法以後,會調用ServiceMethod的invoke方法,這個方法是個抽象方法,具體實如今子類;
最終實現是在HttpServiceMethod的invoke方法裏;
在這裏調用了CallAdapter的adapt方法,將請求call轉化爲對應平臺的請求類型,好比RxJava的類型,這個上面也已經講過了,忘了的朋友,能夠往前翻翻;
從上面的分析能夠看出,Retrofit最重要的點,就是動態代理,在動態代理的時候作了不少邏輯處理,簡化咱們後面的調用等等;
下面咱們來看最終的總結流程圖: