Retrofit
Retrofit 是square公司開發(fā)的一款對OKHttp進(jìn)行了進(jìn)一步封裝的網(wǎng)絡(luò)框架,現(xiàn)在也是android網(wǎng)絡(luò)請求中非常火的一個網(wǎng)絡(luò)請求框架,花了點時間研究了一下Retrofit2.0源碼。
Retrofit2.0原理
Retrofit2.0用了動態(tài)代理技術(shù),通過解析注解生成Http請求,把請求交給OkHttp,然后通過我們設(shè)置的ConverterFactory進(jìn)行serialization和deserialization,最后通過CallAdapter把結(jié)果進(jìn)行進(jìn)一步適配,實現(xiàn)了對Rxjava,Guava和java8的支持。
源碼剖析
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://www.baidu.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
retrofit.create(GitHub.class);
Retrofit實例是使用建造者模式通過Builder類進(jìn)行創(chuàng)建的
建造者模式:將一個復(fù)雜對象的構(gòu)建與表示分離,使得用戶在不知道對象的創(chuàng)建細(xì)節(jié)情況下就可以直接創(chuàng)建復(fù)雜的對象
Retrofit類
public final class Retrofit {
private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();
// 網(wǎng)絡(luò)請求配置對象(對網(wǎng)絡(luò)請求接口中方法注解進(jìn)行解析后得到的對象)
// 作用:存儲網(wǎng)絡(luò)請求相關(guān)的配置,如網(wǎng)絡(luò)請求的方法、數(shù)據(jù)轉(zhuǎn)換器、網(wǎng)絡(luò)請求適配器、網(wǎng)絡(luò)請求工廠、基地
址等
private final HttpUrl baseUrl;
// 網(wǎng)絡(luò)請求的url地址
private final okhttp3.Call.Factory callFactory;
// 網(wǎng)絡(luò)請求器的工廠
// 作用:生產(chǎn)網(wǎng)絡(luò)請求器(Call)
// Retrofit是默認(rèn)使用okhttp
private final List<CallAdapter.Factory> adapterFactories;
// 網(wǎng)絡(luò)請求適配器工廠的集合
// 作用:放置網(wǎng)絡(luò)請求適配器工廠
// 網(wǎng)絡(luò)請求適配器工廠作用:生產(chǎn)網(wǎng)絡(luò)請求適配器(CallAdapter)
// 下面會詳細(xì)說明
private final List<Converter.Factory> converterFactories;
// 數(shù)據(jù)轉(zhuǎn)換器工廠的集合
// 作用:放置數(shù)據(jù)轉(zhuǎn)換器工廠
// 數(shù)據(jù)轉(zhuǎn)換器工廠作用:生產(chǎn)數(shù)據(jù)轉(zhuǎn)換器(converter)
private final Executor callbackExecutor;
// 回調(diào)方法執(zhí)行器
private final boolean validateEagerly;
// 標(biāo)志位
// 作用:是否提前對業(yè)務(wù)接口中的注解進(jìn)行驗證轉(zhuǎn)換的標(biāo)志位
Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories,
Executor callbackExecutor, boolean validateEagerly) {
this.callFactory = callFactory;
this.baseUrl = baseUrl;
this.converterFactories = unmodifiableList(converterFactories);
this.adapterFactories = unmodifiableList(adapterFactories);
// unmodifiableList(list)近似于UnmodifiableList<E>(list)
// 作用:創(chuàng)建的新對象能夠?qū)ist數(shù)據(jù)進(jìn)行訪問,但不可通過該對象對list集合中的元素進(jìn)行修改
this.callbackExecutor = callbackExecutor;
this.validateEagerly = validateEagerly;
}
1、serviceMethod:包含所有網(wǎng)絡(luò)請求信息的對象
2、baseUrl:網(wǎng)絡(luò)請求的url地址
3、callFactory:網(wǎng)絡(luò)請求工廠
4、adapterFactories:網(wǎng)絡(luò)請求適配器工廠的集合
5、converterFactories:數(shù)據(jù)轉(zhuǎn)換器工廠的集合
6、callbackExecutor:回調(diào)方法執(zhí)行器
new Retrofit.Builder()做了什么?我們來揭開神秘面紗
public static final class Builder {
private Platform platform;
private okhttp3.Call.Factory callFactory;
private HttpUrl baseUrl;
private List<Converter.Factory> converterFactories = new ArrayList<>();
private List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
private Executor callbackExecutor;
private boolean validateEagerly;
//Builder類的成員變量與Retrofit類的成員變量是對應(yīng)的 所以Retrofit類的成員變量基本上是通過Builder類進(jìn)行配置
Builder(Platform platform) {
//接收Platform對象(Android平臺)
this.platform = platform;
// 通過傳入BuiltInConverters()對象配置數(shù)據(jù)轉(zhuǎn)換器工廠(converterFactories)
// converterFactories是一個存放數(shù)據(jù)轉(zhuǎn)換器Converter.Factory的數(shù)組
// 配置converterFactories即配置里面的數(shù)據(jù)轉(zhuǎn)換器
converterFactories.add(new BuiltInConverters());
}
public Builder() {
this(Platform.get());
}
//Platform.get()通過源碼可以看到這里面有三種平臺支持android、ios、java,這里返回的是一個Android對象
接下來看一下Platformy源碼
class Platform {
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
private static Platform findPlatform() {
try {
// 支持Android平臺
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
try {
// 支持Java平臺
Class.forName("java.util.Optional");
return new Java8();
} catch (ClassNotFoundException ignored) {
}
try {
// 支持iOS平臺
Class.forName("org.robovm.apple.foundation.NSObject");
return new IOS();
} catch (ClassNotFoundException ignored) {
}
platform)
return new Platform();
}
}
這樣就很清晰了,主要就是這個findPlatform()方法。這里面的代碼,就是判斷當(dāng)前運行的平臺??梢钥吹嚼锩嬗蠥ndroid、Java、IOS。
我們在Android上運行的話,就調(diào)用了return new Android()。
看一下new Android里面是什么東東
static class Android extends Platform {
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
Android繼承了Platform重寫了defaultCallbackExecutor和defaultCallAdapterFactory方法。
defaultCallbackExecutor:返回的是用于執(zhí)行 Callback 的 線程池。可以看到MainThreadExecutor 獲取了主線程的 Looper 并構(gòu)造了一個主線程的 Handler,調(diào)用 Callback 時會將該請求 post 到主線程上去執(zhí)行。這就解釋了為什么請求后完成的回調(diào)都是在主線中。
defaultCallAdapterFactory:將返回的適配類型默認(rèn)為Call類型(如果使用RxJava的話,就可以通過配置.addCallAdapterFactory(RxJavaCallAdapterFactory.create())將配置類型改成Observable。)
baseUrl()
public Builder baseUrl(String baseUrl) {
checkNotNull(baseUrl, "baseUrl == null");
HttpUrl httpUrl = HttpUrl.parse(baseUrl);
if (httpUrl == null) {
throw new IllegalArgumentException("Illegal URL: " + baseUrl);
}
return baseUrl(httpUrl);
}
public Builder baseUrl(HttpUrl baseUrl) {
checkNotNull(baseUrl, "baseUrl == null");
List<String> pathSegments = baseUrl.pathSegments();
if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
}
this.baseUrl = baseUrl;
return this;
}
這里有兩個重載的方法,創(chuàng)建了okhttp3 的 HttpUrl 實例。
addConverterFactory(GsonConverterFactory.create())
public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
往轉(zhuǎn)換工廠集合中添加了我們指定的轉(zhuǎn)換工廠,最后將返回的數(shù)據(jù)類型轉(zhuǎn)換成對應(yīng)的實體類對象的Converter類型。在我們的例子里面 GsonConverterFactory 將選用 GsonConverter 來轉(zhuǎn)換。
build()
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
new Retrofit這里才是創(chuàng)建Retrofit對象的地方,之前的只是一些配置。里面的參數(shù):
callFactory(Call工廠):看到了吧callFactory = new OkHttpClient();,這里用的是okhttp3;
baseUrl(服務(wù)器基本地址):這個我們上面配置過;
converterFactories(對象的序列號/反序列化組件):我們上面配置過。
adapterFactories(適配類型)、callbackExecutor(執(zhí)行 Callback 的線程池):從我們上面提到的platform中獲取默認(rèn)值。
Retrofit 2.0所使用的動態(tài)代理
Retrofit2.0用了動態(tài)代理技術(shù),通過解析注解生成Http請求,把請求交給OkHttp,然后通過我們設(shè)置的ConverterFactory進(jìn)行serialization和deserialization,最后通過CallAdapter把結(jié)果進(jìn)行進(jìn)一步適配,實現(xiàn)了對Rxjava,Guava和java8的支持。
我們看一下retrofit.create()里面是什么鬼?
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(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, 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);
}
//看緩存里面有沒有這個method,要是有,就返回,要是沒有,就生成一個,然后加入緩存
ServiceMethod serviceMethod = loadServiceMethod(method);
//生成一個OkHttpCall對象
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
//調(diào)用OkHttp,然后根據(jù)okHttpCall返回rxjava的Observe對象或者返回Call
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
這里的Platform 其實是檢測retrofit所運行的平臺,是java8還是android還是ios。這里主要是在builder的時候,如果沒有設(shè)置適配器,那么retrofit就會通過運行時的不同平臺,然后選擇不同的CallAdapterFactory。從上面的代碼可以看出,create 方法返回了一個動態(tài)代理對象,通過Github接口生成代理類,并將代理類的實現(xiàn)交給 InvocationHandler 作為具體的實現(xiàn)。這里使用動態(tài)代理的好處是簡化復(fù)雜的網(wǎng)絡(luò)請求和解析、封裝ServiceMethod。
看一下ServiceMethod
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
loadServiceMethod要處理的事物
1.先去serviceMethodCache中查找否存在method(看來這貨是有緩存的,這里采用了LinkedHashMap來緩存這些Method的解析結(jié)果),存在的話跳過第二步;
2.method不存在的話就創(chuàng)建一個,然后添加到緩存中;
3.返回ServiceMethod 對像。
看一下OkHttpCall是如何請求和回調(diào)的
@Override
public void enqueue(final Callback<T> callback) {
if (callback == null) throw new NullPointerException("callback == null");
okhttp3.Call call;
Throwable failure;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
call = rawCall;
failure = creationFailure;
if (call == null && failure == null) {
try {
call = rawCall = createRawCall();
} catch (Throwable t) {
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {
Response<T> response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
callSuccess(response);
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
private void callSuccess(Response<T> response) {
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
}
private okhttp3.Call createRawCall() throws IOException {
Request request = serviceMethod.toRequest(args);
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
這里的call就是okhttp3.Call,是我們外面?zhèn)鬟M(jìn)來的serviceMethod來構(gòu)造出來的okhttp3.Call,在這里通過用call.enqueue(...)把請求交給okhttp的隊列中,然后再通過異步回調(diào)切換到主線程
總結(jié)
啊.....舒了一口氣,整個源碼使用大量的設(shè)計模式
- retrofit.builder 建造者模式
- Android extends Platform 適配器模式
- 各種...Factory 工廠模式
- 在Retrofit中提供了四種CallAdapterFactory: ExecutorCallAdapterFactory(默認(rèn))、GuavaCallAdapterFactory、Java8CallAdapterFactory、RxJavaCallAdapterFactory
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor)) 策略模式 - create(final Class<T> service) 代理模式
等等一系列的設(shè)計模式的組合,使得各個功能模塊高度解耦
本章主要說了一下Retrofit是如何構(gòu)建的,通過動態(tài)代理技術(shù),通過解析注解生成Http請求,把請求交給OkHttp隊列,然后在回調(diào)的這樣一個流程。
點贊加關(guān)注是給我最大的鼓勵!
相關(guān)文章閱讀
Android-設(shè)計模式