前言
充足的時(shí)間才是第一生產(chǎn)力。當(dāng)源碼看多了之后,對(duì)于很多點(diǎn)的梳理上可能就不會(huì)像之前那樣更具體了,本篇主要還是在于對(duì)實(shí)現(xiàn)主流程的分析。Retrofit在之前項(xiàng)目中并沒(méi)有用到過(guò),這次決定來(lái)看一些Retrofit相關(guān)實(shí)現(xiàn)來(lái)了解其中的原理。對(duì)于想要了解Java中的動(dòng)態(tài)代理應(yīng)用,想要用更簡(jiǎn)潔的方式實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求,Retrofit可能是最好的學(xué)習(xí)案例了,之前的項(xiàng)目中在寫(xiě)網(wǎng)絡(luò)請(qǐng)求的時(shí)候,每次都需要寫(xiě)大量的樣板代碼來(lái)構(gòu)造出一個(gè)網(wǎng)絡(luò)請(qǐng)求,代碼一旦增加,犯錯(cuò)誤的概率也就會(huì)增加,維護(hù)成本也就增加,同時(shí)也降低了開(kāi)發(fā)效率,工程化最佳實(shí)踐的目標(biāo)是讓開(kāi)發(fā)者只專(zhuān)注于自己的業(yè)務(wù)邏輯,而不需要關(guān)心下層具體的實(shí)現(xiàn),盡可能暴露少的業(yè)務(wù)無(wú)關(guān)的內(nèi)容給到上層。
基礎(chǔ)使用
對(duì)于Retrofit需要定義一個(gè)接口類(lèi),聲明要請(qǐng)求的接口和其中參數(shù)的傳遞方式,然后通過(guò)調(diào)用create方法就可以構(gòu)造一個(gè)Service類(lèi),調(diào)用相應(yīng)的方法即可幫助我們進(jìn)行網(wǎng)絡(luò)請(qǐng)求的發(fā)送,代碼非常簡(jiǎn)潔,同時(shí)我們也可以通過(guò)對(duì)不同的業(yè)務(wù)模塊分Service的方式來(lái)實(shí)現(xiàn)對(duì)于不同業(yè)務(wù)接口的隔離。
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com")
.addConverterFactory(GsonConverterFactory.create())
.build();
GitHubService service = retrofit.create(GitHubService.class);
源碼分析
Retrofit實(shí)例的創(chuàng)建是主要是進(jìn)行一些信息的配置,這里核心分析的在于其create方法,本篇文章的分析將會(huì)順著create方法的實(shí)現(xiàn)到其最終一個(gè)網(wǎng)絡(luò)請(qǐng)求的調(diào)用,同時(shí)結(jié)合著對(duì)Retrofit源碼的分析來(lái)進(jìn)一步展開(kāi)對(duì)于Java中動(dòng)態(tài)代理實(shí)現(xiàn)的分析。
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];
//對(duì)于代理中的繼承自O(shè)bject的方法還有平臺(tái)方法直接invoke執(zhí)行
@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);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//對(duì)于其它我們定義的方式調(diào)用loadServiceMethod
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
在Retrofit的實(shí)現(xiàn)中create是一個(gè)很關(guān)鍵的方法,也是我們作為源碼分析的一個(gè)切入點(diǎn)。首先看其第一個(gè)方法validateServiceInterface,該方法主要對(duì)傳遞的Service類(lèi)進(jìn)行校驗(yàn),同時(shí)通過(guò)對(duì)注解的處理來(lái)獲取到其中定義方法的相關(guān)信息。具體核心實(shí)現(xiàn)如下。
for (Method method : service.getDeclaredMethods()) {
if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
loadServiceMethod(method);
}
}
對(duì)于service中定義的方法進(jìn)行遍歷,然后通過(guò)調(diào)用loadServcieMethod進(jìn)行相應(yīng)的處理
ServiceMethod<?> loadServiceMethod(Method method) {
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = ServiceMethod.parseAnnotations(this, method);
serviceMethodCache.put(method, result);
}
}
return result;
}
loadServiceMethod方法是Retrofit的整個(gè)框架的實(shí)現(xiàn)的一個(gè)很核心的點(diǎn)了,首先會(huì)從ServiceMethodCache中進(jìn)行相應(yīng)的查找,如果查找到則直接返回,沒(méi)有的話(huà)則會(huì)調(diào)用ServiceMethod的注解處理方法,parseAnnotaion來(lái)生成一個(gè)ServiceMethod,同時(shí)將其加入到緩存之中。那么接下來(lái),我們來(lái)看一下ServiceMethod的相關(guān)實(shí)現(xiàn),和其注解解析方法。
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(method,
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError(method, "Service methods cannot return void.");
}
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
這里的核心實(shí)現(xiàn)在RequestFactory的parseAnnoations和HttpServiceMethod的parseAnnotations方法。接下我們RequestFactory只是通過(guò)retorift和method構(gòu)建了一個(gè)RequestFactory,記錄了方法的參數(shù),返回值類(lèi)型還有注解信息。最后將其作為參數(shù)傳遞至HttpServiceMethod中的parseAnnotations,對(duì)于注解的處理主要是來(lái)將我們?cè)诎l(fā)送網(wǎng)絡(luò)請(qǐng)求時(shí)需要的信息從注解中解析出來(lái),當(dāng)調(diào)用invoke方法的時(shí)候,結(jié)合解析出來(lái)的參數(shù)構(gòu)建一個(gè)網(wǎng)絡(luò)請(qǐng)求。
final ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
在動(dòng)態(tài)代理中當(dāng)我們進(jìn)行一個(gè)方法調(diào)用的時(shí)候?qū)嶋H執(zhí)行代碼如下
loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
對(duì)于loadServiceMethod方法,我們之前已經(jīng)分析過(guò),這里主要根據(jù)方法解析的緩存中查找,然后調(diào)用其invoke方法,來(lái)構(gòu)造一個(gè)OkHttp的請(qǐng)求。然后調(diào)用okhttp的相應(yīng)的請(qǐng)求方法。
總結(jié)
對(duì)于Rerofit在項(xiàng)目中的使用,最上層是我們的業(yè)務(wù)邏輯,下面是我們針對(duì)每一個(gè)業(yè)務(wù)邏輯模塊定義的API,第三層是Retrofit對(duì)于API層向網(wǎng)絡(luò)請(qǐng)求OKhttp層的橋接,最終通過(guò)OkHttp將請(qǐng)求發(fā)送出去。同時(shí)其借助于注解與動(dòng)態(tài)代理讓代碼的實(shí)現(xiàn)變的更優(yōu)雅。借助于接口的形式來(lái)很好的實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求在業(yè)務(wù)層的隔離。注解與動(dòng)態(tài)代理搭配的形式對(duì)于后續(xù)的開(kāi)發(fā)設(shè)計(jì)也是很有啟發(fā)意義的。