前言
之前講過了okhttp的超級(jí)概括的原理解析,okhttp以它優(yōu)秀的線程池設(shè)計(jì),任務(wù)隊(duì)列的分配和轉(zhuǎn)化以及基于責(zé)任鏈模式設(shè)計(jì)的5大攔截器的使用被廣大開發(fā)者間接引入。等等,為啥是間接?你點(diǎn)進(jìn)來的時(shí)候相信已經(jīng)有了答案,當(dāng)然是因?yàn)镽etrofit的橫空出世。當(dāng)我們使用okhttp的時(shí)候肯定得去封裝一層,封裝的時(shí)候得考慮到主、子線程的切換,api返回值的轉(zhuǎn)化處理等等。當(dāng)你哼哧哼哧或者嘻嘻哈哈封裝完畢后,某個(gè)小伙伴說他用不習(xí)慣,他更愿意去做成XXXX+YYYY+okhttp的模式。這個(gè)時(shí)候你是選擇把他k.o.還是自己默默按照他的方式再來一套呢?當(dāng)然是選擇retrofit啦,所以retrofit還是一個(gè)增進(jìn)隊(duì)友之間友誼的軟工具。接下來讓我們一步一步的深挖這個(gè)優(yōu)秀的開源框架是怎么讓友誼的小船越走越遠(yuǎn)的。
使用
public class MainActivity extends AppCompatActivity {
public static final String API_URL = "https://api.github.com";
public void request(View view) {
Retrofit retrofit =
new Retrofit.Builder()
.client(new OkHttpClient())
.callFactory(new OkHttpClient())
.baseUrl(API_URL)
//.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
//.addConverterFactory(GsonConverterFactory.create())
.build();
// Create an instance of our GitHub API interface.
GitHub github = retrofit.create(GitHub.class);
// Create a call instance for looking up Retrofit contributors.
Call<List<Contributor>> call = github.contributors("square", "retrofit");
// Fetch and print a list of the contributors to the library.
new Thread(new Runnable() {
@Override
public void run() {
try {
List<Contributor> contributors = call.execute().body();
Log.e("ss", contributors.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
request(null);
}
public interface GitHub {
@GET("/repos/{owner}/{repo}/contributors")
Call<List<Contributor>> contributors(@Path("owner") String owner, @Path("repo") String repo);
}
public static class Contributor {
public final String login;
public final int contributions;
public Contributor(String login, int contributions) {
this.login = login;
this.contributions = contributions;
}
@Override
public String toString() {
return "Contributor{" +
"login='" + login + '\'' +
", contributions=" + contributions +
'}';
}
}
}
以上代碼是從官網(wǎng)的sample中拷貝的一段,除了線程那邊,其他差不多都一樣,把代碼原樣拷貝到as項(xiàng)目中是可以直接運(yùn)行的。使用上就說到這里(然而并沒有說啥)。相信大家對Retrofit的使用早就爛熟于心,甚至看完我寫的樣例代碼后,起身怒拍桌子。所以這里就不多贅述,我們開始撕源碼。
retrofit的封裝模式其實(shí)就是將okhttp覆蓋了一層更加友好的調(diào)用方式,它本質(zhì)還是得靠okhttp來執(zhí)行網(wǎng)絡(luò)請求,就像一把劍,如果單有鋒利的劍身,沒有劍柄和劍鞘,雖然也能殺敵,但是首先得自損八百。當(dāng)照顧到使用者習(xí)慣后加上了劍柄和劍鞘,甚至再付個(gè)魔,使用起來肯定事半功倍,但是真正起作用的只有劍身。retrofit和okhttp的愛恨糾葛大概說起來就是下面這張圖:
讀源碼最簡單的方式就是從使用上入手,所以,我們就從上面的樣例代碼中開始,看看Retrofit的工作流程。
Retrofit.build()方法究竟做了什么
retrofit使用的是構(gòu)建模式創(chuàng)建實(shí)例,我們重點(diǎn)看下它最終build的時(shí)候做了哪些事情
-
判斷是否有baseUrl
if (baseUrl == null) { throw new IllegalStateException("Base URL required."); }
-
賦值callFactory,這個(gè)callFactory其實(shí)就是okhttpClient
okhttp3.Call.Factory callFactory = this.callFactory; if (callFactory == null) { callFactory = new OkHttpClient(); }
如果沒有值就默認(rèn)給OkHttpClient,使用Retrofit.client(okhttpClient)也是給callFactory賦值
/** * The HTTP client used for requests. * * <p>This is a convenience method for calling {@link #callFactory}. */ public Builder client(OkHttpClient client) { return callFactory(Objects.requireNonNull(client, "client == null")); } /** * Specify a custom call factory for creating {@link Call} instances. * * <p>Note: Calling {@link #client} automatically sets this value. */ public Builder callFactory(okhttp3.Call.Factory factory) { this.callFactory = Objects.requireNonNull(factory, "factory == null"); return this; }
-
賦值callbackExecutor
Executor callbackExecutor = this.callbackExecutor; if (callbackExecutor == null) { callbackExecutor = platform.defaultCallbackExecutor(); }
通過上面的代碼可以看到,如果沒有設(shè)置,就默認(rèn)給出platform.defaultCallbackExecutor(),那這個(gè)默認(rèn)又個(gè)是啥?callbackExecutor究竟是干嘛用的?我們點(diǎn)進(jìn)去康康
class Platform { ... @Nullable Executor defaultCallbackExecutor() { return null; } ... }
Platform,顧名思義,就是平臺(tái),我們初步判斷這個(gè)類其實(shí)就是選擇平臺(tái)用的,但是return null???,直覺告訴我事出反常必有妖,肯定是哪里把這個(gè)方法給重寫了。
static final class Android extends Platform { ... @Override public Executor defaultCallbackExecutor() { return new MainThreadExecutor(); } ... }
果然是這樣,是一個(gè)叫Android的類復(fù)寫了這個(gè)方法,那是在哪里對這個(gè)Platform進(jìn)行賦值了呢?
public static final class Retrofit.Builder { ... public Builder() { this(Platform.get()); } ... }
其實(shí)就是在創(chuàng)建Retrofit的Builder的時(shí)候就已經(jīng)對所選平臺(tái)進(jìn)行了賦值,具體的賦值方法如下
class Platform { private static final Platform PLATFORM = findPlatform(); static Platform get() { return PLATFORM; } private static Platform findPlatform() { return "Dalvik".equals(System.getProperty("java.vm.name"))//就是這一行代碼確定了平臺(tái) ? new Android() // : new Platform(true); } ... }
確定了平臺(tái)后,再看看Android平臺(tái)下是怎么賦值defaultCallbackExecutor的
static final class Android extends Platform { ... @Override public Executor defaultCallbackExecutor() { return new MainThreadExecutor(); } ... static final class MainThreadExecutor implements Executor { private final Handler handler = new Handler(Looper.getMainLooper()); @Override public void execute(Runnable r) { handler.post(r); } } }
defaultCallbackExecutor方法就是構(gòu)造了一個(gè)MainThreadExecutor的實(shí)例,這個(gè)實(shí)例里面有個(gè)new Handler(Looper.getMainLooper());很熟悉有木有,看到這里我們大概能猜出來了,Retrofit.callbackExecutor這個(gè)成員變量其實(shí)就是一個(gè)用來切換線程的東東,在執(zhí)行了execute方法后會(huì)切換到主線程。
-
賦值callAdapterFactories
// Make a defensive copy of the adapters and add the default Call adapter. List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories); callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
上述代碼中callAdapterFactories,就是一個(gè)工廠模式,這里是做成了列表,表示能創(chuàng)建不同的callAdapter,這個(gè)callAdapter其實(shí)就是類比到okhttp中的Call,網(wǎng)絡(luò)請求的關(guān)鍵一步(call.equeue(),call.execute())就是由這個(gè)來做的(先這么認(rèn)為,建立一個(gè)概念)。這里要看看最后那行platform.defaultCallAdapterFactories(callbackExecutor),是不是感覺很熟悉,這里其實(shí)就是做了兩件事情,第一步:把你之前在Retrofit.addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build()中添加的RxJava2CallAdapterFactory這個(gè)實(shí)體給放到callAdapterFactories列表中。第二步:將平臺(tái)中默認(rèn)的callAdapterFactory也放在這個(gè)列表中。那么平臺(tái)默認(rèn)的AdapterFactory長啥樣?
List<? extends CallAdapter.Factory> defaultCallAdapterFactories( @Nullable Executor callbackExecutor) { DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor); return hasJava8Types ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory) : singletonList(executorFactory); }
這個(gè)方法中也做了兩件事,首先創(chuàng)建一個(gè)平臺(tái)默認(rèn)的callAdapterFactory(DefaultCallAdapterFactory),然后判斷hasJava8Types,如果為false,就將這個(gè)DefaultCallAdapterFactory放入到列表中并返回。使用singletonList方法是使用定長列表,為了減少內(nèi)存分配(要不人怎么能去寫開源框架呢,什么事情都做到極致??——暗示點(diǎn)贊)。如果為true那就除了DefaultCallAdapterFactory外還要額外加一個(gè)CompletableFutureCallAdapterFactory,那hasJava8Types是何時(shí)被確定下來的呢?
class Platform { ... Platform(boolean hasJava8Types) { this.hasJava8Types = hasJava8Types; ... } }
上述代碼得知,是通過構(gòu)造方法確認(rèn)的,所以要去Android類下看看Android是怎么確定這個(gè)值的
static final class Android extends Platform { Android() { super(Build.VERSION.SDK_INT >= 24); } ... }
很簡單,只有當(dāng)sdk>=24時(shí)才為true,為什么要做這樣的一個(gè)判斷?因?yàn)閖ava1.8有一個(gè)新特性叫CompletableFuture,這里不去深挖了,感興趣的同學(xué)可以狗哥一下(狗哥一下,就是強(qiáng)大??——暗示點(diǎn)贊)。
-
賦值converterFactories
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. converterFactories.add(new BuiltInConverters()); converterFactories.addAll(this.converterFactories); converterFactories.addAll(platform.defaultConverterFactories());
converterFactories就是給服務(wù)端的返回值進(jìn)行一個(gè)轉(zhuǎn)化用的,這里面的代碼做了幾件事情。
- 創(chuàng)建一個(gè)List<Converter.Factory> converterFactories列表,這個(gè)列表的長度設(shè)置成在build中配置的converterFactories的長度加平臺(tái)中的默認(rèn)ConverterFactories的長度+1
- 添加BuiltInConverters轉(zhuǎn)換工廠,這里給出了注釋,狗哥翻譯:首先添加內(nèi)置轉(zhuǎn)換器工廠。 這可以防止覆蓋其行為,但也可以確保使用使用所有類型的轉(zhuǎn)換器時(shí)的正確行為。大概意思就是個(gè)內(nèi)置轉(zhuǎn)換器,用來處理一些奇葩的返回,比如Stream,Buffer,Void,甚至kotlin中的Unit
- 添加用戶自定義的轉(zhuǎn)換工廠
- 添加平臺(tái)中的轉(zhuǎn)化工廠,這個(gè)和第一步中的platform.defaultConverterFactoriesSize()平臺(tái)工廠列表長度相呼應(yīng),如果平臺(tái)中有轉(zhuǎn)換工廠列表就有size,如果沒有size 就等于0。
平臺(tái)默認(rèn)工廠列表有哪些?看代碼
class Platform { ... List<? extends Converter.Factory> defaultConverterFactories() { return hasJava8Types ? singletonList(OptionalConverterFactory.INSTANCE) : emptyList(); } int defaultConverterFactoriesSize() { return hasJava8Types ? 1 : 0; } ... }
我們看到了熟悉的hasJava8Types,這個(gè)就不多說了,如果為true的時(shí)候會(huì)添加一個(gè)這個(gè)工廠,同時(shí)返回的defaultConverterFactoriesSize會(huì)等于1,和上一段代碼相呼應(yīng)。
-
在一切都準(zhǔn)備就緒后,一個(gè)Retrofit實(shí)例就成功創(chuàng)建出來了
return new Retrofit( callFactory, baseUrl, unmodifiableList(converterFactories), unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly); }
上面代碼中的unmodifiableList,其實(shí)是Collections.unmodifiableList()這個(gè)方法的大概意思就是,你不能這樣去添加一個(gè)factory工廠:Retrofit.getConverterFactories().add(......),如果這么做就會(huì)報(bào)錯(cuò)。這樣寫的意圖是為了代碼的健壯性。
前菜結(jié)束,下面來幾個(gè)正餐
Retrofit.create()方法究竟做了什么
直接上代碼
public <T> T create(final Class<T> service) {
validateServiceInterface(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 @Nullable Object invoke(Object proxy, Method method, @Nullable 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);
}
args = args != null ? args : emptyArgs;
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
唉咦!!Proxy.newProxyInstance,乍一看仿佛又看到了熟悉的東西,仔細(xì)一看,還確實(shí)是動(dòng)態(tài)代理,代理就是將某個(gè)對象的一些方法交給第二個(gè)對象(代理對象)去完成。舉一個(gè)很形象的例子。
特能謅公司產(chǎn)了型號(hào)為never-stop-740的電瓶車(以下簡寫740電瓶車),這款740電瓶車根本剎不住車,N女士當(dāng)時(shí)不知道有問題,買回來后出了事情,去特能謅公司討要說法,但是無果,這時(shí)候N女士需要一個(gè)更加強(qiáng)大的人來代替她去要說法。
于是她就委托X律師全權(quán)處理剎車失靈的事情。X律師一開始也和N女士一樣去特能謅先去討要說法,但是無果,這個(gè)時(shí)候X律師就想辦法要到了740電瓶車的出廠清單,然后找專業(yè)人士去分析這個(gè)清單,最后實(shí)錘740電瓶車確實(shí)是因?yàn)榧夹g(shù)問題導(dǎo)致剎車失靈,然后X律師拿著740電瓶車剎車失靈的清單報(bào)告將特能謅公司告上了法庭,在充足的證據(jù)面前特能謅不得不對N女士進(jìn)行了道歉,X律師完成了N女士的討回公道的請求。
我們看看N女士的整個(gè)過程,首先N女士有一個(gè)“討回公道”的要求,但是因?yàn)樘啬苤a比較能謅,顯然N女士自己不能完成,于是她就找了代理X律師,X律師代理后首先也是去特能謅討說法(和N女士一樣),但是X律師的手段比N女士多得多,又是聯(lián)系廠商出報(bào)告,又是找專業(yè)人士分析報(bào)告,又是將特能謅告上法庭,最終完成了N女士“討回公道”的需要。
從上面的例子中可以看出代理的作用就是將原來實(shí)體可以實(shí)現(xiàn)的給實(shí)現(xiàn)掉,甚至還能把原來實(shí)體的功能進(jìn)行增強(qiáng),從代碼中看
public interface GitHub {
@GET("/repos/{owner}/{repo}/contributors")
Call<List<Contributor>> contributors(@Path("owner") String owner, @Path("repo") String repo);
}
這里的GitHub類可以看成是N女士,她有一個(gè)訴求就是執(zhí)行contributors方法,獲取到git的倉庫列表。顯而易見,你GitHub只不過是一個(gè)小小接口,啥都干不了,你還想去通過網(wǎng)絡(luò)請求去獲取git倉庫列表?真是小小接口,可笑可笑。就像是N女士面對特能謅討說法束手無策一樣。但是這時(shí)候GitHub接口去找到了動(dòng)態(tài)代理Proxy.newProxyInstance(...),這個(gè)動(dòng)態(tài)代理可以看成是X律師,這個(gè)動(dòng)態(tài)代理可以把GitHub接口中配置的東西(@Get()中的api,contributors方法中的各種請求需要的參數(shù))全部轉(zhuǎn)化為okhttp需要的參數(shù),然后順便再將請求通過okhttp發(fā)送出去,甚至當(dāng)數(shù)據(jù)返回時(shí)還能幫忙把數(shù)據(jù)解析成想要的格式。這真是“山重水復(fù)疑無路,柳暗花明又一村”啊。
那為什么要選擇動(dòng)態(tài)代理呢,如果是選擇靜態(tài)代理,那GitHub有多少種方法,在靜態(tài)代理中就要增加多少個(gè)對應(yīng)的方法。動(dòng)態(tài)代理采用了反射機(jī)制,將所有的請求全部都流經(jīng)這個(gè)動(dòng)態(tài)代理的invoke()方法中,對于使用者來說如果你將來想要往里面添加請求,比如獲取某個(gè)列表的詳情,那只要像contributors方法一樣添加一個(gè)聲明類的方法即可,動(dòng)態(tài)代理會(huì)幫你處理剩下的事情。對,沒錯(cuò),是耗性能,但是retrofit用了這么久,它不香嗎?
接下來我們看看這個(gè)動(dòng)態(tài)代理究竟幫助我們做了哪些重要的事情
首先要明確一個(gè)重要的概念
GitHub github = retrofit.create(GitHub.class);
上述代碼執(zhí)行完后其實(shí)只是創(chuàng)建了一個(gè)代理,下述代碼中的InvocationHandler.invoke方法并不會(huì)馬上被執(zhí)行
public <T> T create(final Class<T> service) {
validateServiceInterface(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 @Nullable Object invoke(Object proxy, Method method, @Nullable 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);
}
args = args != null ? args : emptyArgs;
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);//代碼30
}
});
}
那什么時(shí)候被執(zhí)行?就是執(zhí)行下述代碼的時(shí)候
Call<List<Contributor>> call = github.contributors("square", "retrofit");
為什么呢?當(dāng)GitHub github = retrofit.create(GitHub.class);這個(gè)代碼執(zhí)行后,實(shí)際上github 這個(gè)類已經(jīng)不是它自己了,而是一個(gè)代理(X律師)。那代理總歸是能代替原來的實(shí)體做事情的,它做的事情都會(huì)流經(jīng)invoke。那原來的實(shí)體要做什么呢,就是執(zhí)行contributors()方法。動(dòng)態(tài)代理中的原理也需要深入源碼去分析,現(xiàn)在只要知道只有在代理執(zhí)行方法的時(shí)候才會(huì)執(zhí)行invoke方法就行,以后會(huì)出一個(gè)動(dòng)態(tài)代理源碼分析的記錄。而invoke()方法中的method,就相當(dāng)于contributors()這個(gè)方法
明確了這一點(diǎn)后我們看看github(代理).contributors方法會(huì)執(zhí)行哪些東西:
private final Platform platform = Platform.get(); 獲取當(dāng)前平臺(tái)
-
return platform.isDefaultMethod(method) ? platform.invokeDefaultMethod(method, service, proxy, args) : loadServiceMethod(method).invoke(args);
執(zhí)行方法
其中這里首先會(huì)判斷下當(dāng)前需要執(zhí)行的方法是不是默認(rèn)方法,我們跟進(jìn)去看一眼
boolean isDefaultMethod(Method method) { return hasJava8Types && method.isDefault(); }
hasJava8Types我們先不管,因?yàn)樗黷rue和false都有可能。跟進(jìn)method.isDefault()方法
/** * Returns {@code true} if this method is a default * method; returns {@code false} otherwise. * * A default method is a public non-abstract instance method, that * is, a non-static method with a body, declared in an interface * type. * * @return true if and only if this method is a default * method as defined by the Java Language Specification. * @since 1.8 */ public boolean isDefault() { // Android-changed: isDefault() implemented using Executable. return super.isDefaultMethodInternal(); }
看注釋,這又是一個(gè)java8的新特性,意思是如果被default修飾符修飾那就返回true,否則返回false。這里再多一嘴這個(gè)新特性
通常我們寫接口類的方法時(shí)一般只能寫它的類似聲明的一個(gè)方法,而不能寫具體的實(shí)現(xiàn),但是java8中你一旦加入了這個(gè)default修飾符后,你就可以去寫具體的實(shí)現(xiàn)。就像這樣
interface MyInterface { default void eat() { System.out.println("I eat beef"); } }
意思是如果有個(gè)類你implement這個(gè)接口類,那你不去實(shí)現(xiàn)這個(gè)eat()方法,那我就調(diào)用默認(rèn)的 System.out.println("I eat beef");
顯然一般來說我們不可能多去寫這么個(gè)東西,所以method.isDefault()肯定返回false,從而platform.isDefaultMethod(method) 這個(gè)肯定返回false,從而肯定會(huì)執(zhí)行l(wèi)oadServiceMethod(method).invoke(args)這個(gè)方法,這個(gè)方法分兩步走
第一步:loadServiceMethod(method),我們跟進(jìn)去看看
public final class Retrofit { private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>(); ... ServiceMethod<?> loadServiceMethod(Method method) { ServiceMethod<?> result = serviceMethodCache.get(method);//代碼1 if (result != null) return result; synchronized (serviceMethodCache) { result = serviceMethodCache.get(method); if (result == null) { result = ServiceMethod.parseAnnotations(this, method);//代碼2 serviceMethodCache.put(method, result); } } return result; } ... }
這個(gè)方法中
代碼1
首先從serviceMethodCache這個(gè)map中找method對應(yīng)的ServiceMethod,如果沒有就走代碼2
新建一個(gè),然后通過key = method,value = ServiceMethod的方式將ServiceMethod存入map中。為啥要這樣干,很顯然,這是為了性能,ServiceMethod.parseAnnotations方法中存在了大量的反射,反射本身是很耗性能的,我們的ServiceMethod可謂得之不易,非常珍貴,這么珍貴的資源當(dāng)然得存起來,萬一下次再用,我就不用重新再次拼命反射獲得了。再深入一下,看看ServiceMethod.parseAnnotations究竟是干嘛的abstract class ServiceMethod<T> { static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) { RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method); ... return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory); } ... }
從上述代碼看出這里會(huì)做兩件事情
RequestFactory.parseAnnotations(retrofit, method);
和return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
,接下來我們展開講講這兩個(gè)方法
RequestFactory.parseAnnotations(retrofit, method)方法究竟做了什么
看下面的代碼
final class RequestFactory {
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
...
RequestFactory build() {
for (Annotation annotation : methodAnnotations) {//代碼1
parseMethodAnnotation(annotation);//代碼3
}
...
int parameterCount = parameterAnnotationsArray.length;//代碼4
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
parameterHandlers[p] =
parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
}
...
return new RequestFactory(this);//代碼6
}
...
}
...
static final class Builder {
...
final Annotation[] methodAnnotations;
final Annotation[][] parameterAnnotationsArray;
...
Builder(Retrofit retrofit, Method method) {
...
this.methodAnnotations = method.getAnnotations();//代碼2:獲取方法上的注解
this.parameterAnnotationsArray = method.getParameterAnnotations();//代碼5:獲取方法中參數(shù)的注解
...
}
}
調(diào)用了parseAnnotations方法后,會(huì)直接調(diào)用build()方法,這個(gè)build方法首先會(huì)執(zhí)行代碼1
這個(gè)循環(huán)的作用就是取出方法上的所有注解以及內(nèi)容(代碼2
中展示了怎么獲取方法上的注解),然后進(jìn)行一個(gè)url的字符拼接和確定是post/get/put/...的請求。具體的方法就在代碼3
中,我們跟進(jìn)去看看
private void parseMethodAnnotation(Annotation annotation) {
//設(shè)置是什么類型的請求
if (annotation instanceof DELETE) {
parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);//代碼4
} else if (annotation instanceof GET) {
parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
}
...
//設(shè)置頭部
else if (annotation instanceof retrofit2.http.Headers) {
String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
if (headersToParse.length == 0) {
throw methodError(method, "@Headers annotation is empty.");
}
headers = parseHeaders(headersToParse);
}
...
}
其中代碼4
中的第二個(gè)參數(shù)取的就是url后面的東西,比如我的樣例中請求方法的頭部是這樣的@GET("/repos/{owner}/{repo}/contributors") 那取的就是括號(hào)中的字符,具體怎么解析的,我們看代碼
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
if (this.httpMethod != null) {
throw methodError(
method,
"Only one HTTP method is allowed. Found: %s and %s.",
this.httpMethod,
httpMethod);
}
this.httpMethod = httpMethod;
this.hasBody = hasBody;
if (value.isEmpty()) {
return;
}
// Get the relative URL path and existing query string, if present.
int question = value.indexOf('?');
if (question != -1 && question < value.length() - 1) {
// Ensure the query string does not have any named parameters.
String queryParams = value.substring(question + 1);
//這里是大括號(hào)的正則
Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams);
this.relativeUrl = value;
//這里是將所有的大括號(hào)中的內(nèi)容根據(jù)正則取出賦值給relativeUrlParamNames
this.relativeUrlParamNames = parsePathParameters(value);
}
簡單來說,就是保存當(dāng)前是什么類型的請求,然后請求中的?后面的內(nèi)容取出來,還有就是替換掉{XXX}中包含的東西并保存好。
代碼4開始,就是獲取方法中參數(shù)的注解并保存到ParameterHandler<?>[] parameterHandlers中,我們可以看到,在代碼5中實(shí)際上是用了二維數(shù)組來保存方法中參數(shù)的注解的,這是因?yàn)椋椒ㄖ械膮?shù)注解可以有多個(gè)比如這個(gè)樣子
Call<List<Contributor>> contributors(@Field ("ss")@Path("owner") String owner)
所以parameterAnnotationsArray的含義是parameterAnnotationsArray[參數(shù)][注解]
,參數(shù)可以有很多個(gè),每個(gè)參數(shù)中對應(yīng)的注解也可以有很多個(gè)
最后執(zhí)行代碼6
返回,接下來分析HttpServiceMethod.parseAnnotations
HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory)方法究竟做了什么
總體來說這個(gè)方法就是做了兩件事
- 選擇合適此次請求的CallAdapter
- 選擇合適此次請求的Converter
為什么是“合適此次請求”?很簡單,我們構(gòu)建Retrofit的時(shí)候肯定可以這樣干
new Retrofit.Builder()
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactoryB.create())
.addCallAdapterFactory(RxJava2CallAdapterFactoryC.create())
.addConverterFactory(GsonConverterFactory.create())
.addConverterFactory(GsonConverterFactoryB.create())
.addConverterFactory(GsonConverterFactoryC.create())
那你搞出這么多的CallAdapter和Converter的工廠,真正在請求的時(shí)候,Retrofit肯定只會(huì)用到一個(gè)啊,那不得通過返回值來篩選一下子啊,聽懂掌聲——暗示點(diǎn)贊
具體我們跟進(jìn)代碼中看看
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
boolean continuationWantsResponse = false;
boolean continuationBodyNullable = false;
Annotation[] annotations = method.getAnnotations();
Type adapterType;
if (isKotlinSuspendFunction) {//代碼7
...
} else {
adapterType = method.getGenericReturnType();//代碼8
}
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);//代碼10
Type responseType = callAdapter.responseType();
...
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);//代碼11
okhttp3.Call.Factory callFactory = retrofit.callFactory;
if (!isKotlinSuspendFunction) {
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);//代碼9
} else if (continuationWantsResponse) {
...
} else {
...
}
}
首先要明確一點(diǎn),HttpServiceMethod是繼承ServiceMethod的,然后我們往里面看看。
首先看到代碼7
這是一個(gè)判斷是否為kotlin的Suspend關(guān)鍵字的掛起方法,顯然不是,所以執(zhí)行到了代碼8
這個(gè)代碼的意思是獲取請求網(wǎng)絡(luò)方法的返回值,想想也對,我們要確認(rèn)是哪個(gè)CallAdapter或者Convert那不得從返回值的類型入手嘛。
接下來執(zhí)行到了代碼10
,這段代碼就是幫我們選擇合適的CallAdapter的,究竟是怎么篩選的呢,來來來我們深入了解下
abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
...
private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {
try {
//noinspection unchecked
return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);//代碼12
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(method, e, "Unable to create call adapter for %s", returnType);
}
}
...
}
public final class Retrofit {
...
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);//代碼13
}
public CallAdapter<?, ?> nextCallAdapter(
@Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {//代碼15
...
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);//代碼14
if (adapter != null) {
return adapter;
}
}
...
}
如上述代碼,首先我們的代碼10
執(zhí)行后會(huì)有一系列的跳轉(zhuǎn):代碼10
->代碼12
->代碼13
->代碼15
,直接看代碼15
,代碼15
中有一個(gè)skipPast的參數(shù)是告訴程序,你不用給我找從第一個(gè)CallAdapter.Factory到skipPast之間的所有CallAdapter.Factory了,你給我直接從skipPast后面開始for循環(huán)。顯然代碼13
傳的是null,所以暫時(shí)不用管,想要繼續(xù)擴(kuò)展的可以看下SkipCallbackExecutor
這個(gè)注解。
代碼15
以后是一個(gè)for循環(huán),這個(gè)循環(huán)的作用是找出符合條件的CallAdapter
,其中最主要的代碼是代碼14
,如果循環(huán)過程中代碼14
返回的不為null,就說明已經(jīng)找到合適的了,并直接返回結(jié)果,我們進(jìn)去代碼14
的get(returnType, annotations, this)
方法中一探究竟
abstract class Factory {
/**
* Returns a call adapter for interface methods that return {@code returnType}, or null if it
* cannot be handled by this factory.
*/
public abstract @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit);//代碼16
...
}
final class DefaultCallAdapterFactory extends CallAdapter.Factory {
...
@Override
public @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit) {
final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);
final Executor executor =//代碼17
Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
? null
: callbackExecutor;
return new CallAdapter<Object, Call<?>>() {//代碼18
@Override
public Type responseType() {
return responseType;
}
@Override
public Call<Object> adapt(Call<Object> call) {
return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
}
};
}
...
}
執(zhí)行到代碼16
的時(shí)候就會(huì)代碼14
中對應(yīng)取到的CallAdapter.Factory
來執(zhí)行g(shù)et()方法,就拿DefaultCallAdapterFactory來舉個(gè)例子,代碼17
中其實(shí)就是判斷當(dāng)前是否需要跳過,如果是跳過就給Executor = null如果不要跳過那就給他原來賦值的callbackExecutor,這個(gè)callbackExecutor之前講過,安卓平臺(tái)默認(rèn)就是切換線程用的,代碼18
中就返回了一個(gè)CallAdapter
,到此代碼10
就這樣分析完畢
接下來我們看看代碼11
,這段代碼其實(shí)就是幫我們篩選出符合條件的Converter的,老規(guī)矩,進(jìn)去繼續(xù)深入聊聊
abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
...
private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter(
Retrofit retrofit, Method method, Type responseType) {
Annotation[] annotations = method.getAnnotations();
try {
return retrofit.responseBodyConverter(responseType, annotations);//代碼19
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(method, e, "Unable to create converter for %s", responseType);
}
}
...
}
public final class Retrofit {
...
public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
return nextResponseBodyConverter(null, type, annotations);//代碼20
}
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(//代碼23
@Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
Objects.requireNonNull(type, "type == null");
Objects.requireNonNull(annotations, "annotations == null");
int start = converterFactories.indexOf(skipPast) + 1;//代碼21
for (int i = start, count = converterFactories.size(); i < count; i++) {
Converter<ResponseBody, ?> converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);//代碼22
if (converter != null) {
//noinspection unchecked
return (Converter<ResponseBody, T>) converter;
}
}
...
}
}
上述代碼可以看到,過濾Converter和過濾CallAdapter的套路大同小異,我們看看代碼流向:代碼19
->代碼20
->代碼23
前面幾個(gè)代碼流向就不多說了,直接看代碼21
,這里也是過濾掉了帶有SkipCallbackExecutor
的Converter,然后不斷循環(huán)之前配的converterFactories
,看代碼22
循環(huán)體中會(huì)調(diào)用responseBodyConverter()方法,如果返回不為null就表示找到了合適的Converter,進(jìn)入responseBodyConverter方法康康
abstract class Factory {
public @Nullable Converter<ResponseBody, ?> responseBodyConverter(
Type type, Annotation[] annotations, Retrofit retrofit) {
return null;
}
}
返回null,很明顯是通過子類來實(shí)現(xiàn)的,以GsonConverterFactory為例
public final class GsonConverterFactory extends Converter.Factory {
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonResponseBodyConverter<>(gson, adapter);
}
...
}
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();
}
}
}
看上述代碼其實(shí)就是把返回的值轉(zhuǎn)化為json格式,這邊就貼兩段代碼,具體也沒啥好講的,實(shí)在有不明白的可以在評(píng)論區(qū)留個(gè)言。
最后我們再看一眼代碼9
,這段代碼把剛才篩選出的CallAdater和Converter作為參數(shù)給了CallAdapted
的構(gòu)造函數(shù)生成了一個(gè)新的CallAdapted實(shí)體,注意:是CallAdapted 不是CallAdater,CallAdated是最終形態(tài),他是繼承HttpServiceMethod的。
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT>
到這里為止所有的東西已經(jīng)就緒,現(xiàn)在就差調(diào)用okhttp,接下來會(huì)詳細(xì)講解Retrofit是如何調(diào)用okhttp的
生成Call
我們的樣例代碼中有這么一行
Call<List<Contributor>> call = github.contributors("square", "retrofit");
那這個(gè)call是怎么來的?嘿嘿,不要忘了,我們分析到現(xiàn)在還只是分析了動(dòng)態(tài)代理中invoke方法中的loadServiceMethod(method)
返回值是怎么來的,那返回值后面還低調(diào)地寫了一個(gè)方法:.invoke(args)
,低調(diào)但是也不平凡,這個(gè)方法直接返回了Call,且聽我娓娓道來。
老規(guī)矩,跟代碼
abstract class ServiceMethod<T> {
...
abstract @Nullable T invoke(Object[] args);//代碼24
}
abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
...
@Override
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);//代碼25
}
protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);//代碼26
...
}
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
private final CallAdapter<ResponseT, ReturnT> callAdapter;
...
@Override
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return callAdapter.adapt(call);//代碼27
}
}
public interface CallAdapter<R, T> {
...
T adapt(Call<R> call);//代碼28
...
}
代碼流向是這樣:代碼24
->代碼25
->代碼26
->代碼27
->代碼28
,到代碼28
是不是發(fā)現(xiàn)走不下去了?那就對了,你看看28是在哪個(gè)類下?CallAdapter,是不是很熟悉?沒錯(cuò)這個(gè)就是之前被我們循環(huán)篩選,選出來的工廠造出來地CallAdapter,你回去看一眼代碼18
,代碼27執(zhí)行后必然會(huì)執(zhí)行下面的代碼(代碼18
匿名類中的方法)
@Override
public Call<Object> adapt(Call<Object> call) {
return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
}
那么這個(gè)executor是什么?當(dāng)然是Android(extends Platform)平臺(tái)的類中的MainThreadExecutor啦,當(dāng)然不可能為null啦,所以肯定會(huì)是新建一個(gè)ExecutorCallbackCall實(shí)例,下面是這個(gè)類的代碼
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@Override
public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
delegate.enqueue(
new Callback<T>() {
@Override
public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(
() -> {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on
// cancellation.
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
});
}
@Override
public void onFailure(Call<T> call, final Throwable t) {
callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
}
});
}
@Override
public boolean isExecuted() {
return delegate.isExecuted();
}
@Override
public Response<T> execute() throws IOException {//代碼29
return delegate.execute();
}
@Override
public void cancel() {
delegate.cancel();
}
@Override
public boolean isCanceled() {
return delegate.isCanceled();
}
@SuppressWarnings("CloneDoesntCallSuperClone") // Performing deep clone.
@Override
public Call<T> clone() {
return new ExecutorCallbackCall<>(callbackExecutor, delegate.clone());
}
@Override
public Request request() {
return delegate.request();
}
@Override
public Timeout timeout() {
return delegate.timeout();
}
}
如果你曾經(jīng)使用過okhttp,可以在這里看到,幾個(gè)熟悉的方法enqueue,execute,timeout...我的天,retrofit居然把okhttp中的Call又自己做了一層封裝:retrofit2.Call !!!
Retrofit:okhttp老兄,有人說你不好用,連個(gè)線程切換都沒有,還要人去哼哧哼哧地封裝,你早晚讓人給斃了
okhttp(驚恐臉):那怎么辦,老弟你可得給我支支招啊
Retrofit:也不是不行,你跟我合作,我可是出了名地好用,到時(shí)候把你封裝進(jìn)來,用的人就多了啊
okhttp(長嘆一口氣):多謝老弟,老弟費(fèi)心,來根煙
okhttp彎下腰遞了一根煙給Retrofit
Retrofit(陰險(xiǎn)內(nèi)心獨(dú)白):我調(diào)你用我自己封裝的Call,讓程序員用我的時(shí)候完全感知不到你的存在,我看幾年后誰還記得你,咩,哈哈哈哈~
這究竟是道德的淪陷還是。。。
其實(shí)是因?yàn)镽etrofit設(shè)計(jì)初衷就是想靈活適配網(wǎng)絡(luò)請求框架的,這樣做的話可以體現(xiàn)出我是獨(dú)立的,你們?nèi)魏稳硕伎梢院臀液献鳎灰龊苌俚倪m配。
只不過目前為止還是只適配了okhttp。。。
現(xiàn)在Call已經(jīng)生成了,我們接著樣例代碼往下走
List<Contributor> contributors = call.execute().body();
執(zhí)行網(wǎng)絡(luò)請求
當(dāng)執(zhí)行了call.execute()后就直接執(zhí)行到了代碼29
,在這個(gè)方法中發(fā)現(xiàn)它執(zhí)行的是delegate.execute();我們猜測,這個(gè)delegate其實(shí)就是okhttp的call,證據(jù)如下
首先我們再回到夢開始的地方——代理執(zhí)行invoke方法的地方見代碼30
進(jìn)入invoke方法,我們再看這里面有個(gè)啥
@Override
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);//代碼31
return adapt(call, args);
}
所有的請求都會(huì)走這個(gè)invoke。我們看看代碼31
,這段代碼返回的東西,就是我們之前分析的retrofit2.Call,如果能證明OkHttpCall里面的execute方法確實(shí)調(diào)用了Okhttp3.Call.execute()方法,那整個(gè)流程就通了。看代碼
final class OkHttpCall<T> implements Call<T> {
@Override
public Response<T> execute() throws IOException {
okhttp3.Call call;//代碼32
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
call = getRawCall();//代碼33
}
if (canceled) {
call.cancel();
}
return parseResponse(call.execute());
}
...
@GuardedBy("this")
private okhttp3.Call getRawCall() throws IOException {//代碼34
okhttp3.Call call = rawCall;//代碼35
if (call != null) return call;
...
// Create and remember either the success or the failure.
try {
return rawCall = createRawCall();//代碼36
} catch (RuntimeException | Error | IOException e) {
throwIfFatal(e); // Do not assign a fatal error to creationFailure.
creationFailure = e;
throw e;
}
}
...
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = callFactory.newCall(requestFactory.create(args));//代碼37
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
}
代碼流向:代碼33
->代碼34
->代碼35
->代碼36
->代碼37
,還記得callFactory的賦值嗎?對的,就是如果在build構(gòu)建Retrofit時(shí)沒有賦值,那就默認(rèn)OkhttpClient,下面的代碼幫助回憶一下:
public Retrofit build() {
...
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
...
}
證畢,結(jié)果:實(shí)錘retrofit2.Call == okhttp3.Call
接下來執(zhí)行execute方法其實(shí)就是okhttp3.Call.execute(),我之前寫了一篇文章是以okhttp3.Call.equeue()為例的,其實(shí)原理都差不多,有興趣的可以看一下我的文章:okhttp3原理解析——概覽(非常概括)
結(jié)語
頭一回寫這么長篇的源碼解析,寫到這里其實(shí)也漲了不少的知識(shí),閱讀源碼確實(shí)是一個(gè)很好的習(xí)慣,都說閱讀書本是在和圣賢交流,交流多了就能成為圣賢。那閱讀優(yōu)秀源碼其實(shí)也是在和大神交流,交流多了不說能成為大神,至少對以后的學(xué)習(xí)和能力的提升都是一筆不小的財(cái)富。Retrofit確實(shí)是一個(gè)很優(yōu)秀的開源框架,我也是看了3天才大致了解里面的工作流程,好的東西真的是每次看都能發(fā)現(xiàn)新的知識(shí),每次都能將自己的認(rèn)知升那么一小段。