Retrofit
Retrofit 是square公司開發的一款對OKHttp進行了進一步封裝的網絡框架,現在也是android網絡請求中非常火的一個網絡請求框架,花了點時間研究了一下Retrofit2.0源碼。
Retrofit2.0原理
Retrofit2.0用了動態代理技術,通過解析注解生成Http請求,把請求交給OkHttp,然后通過我們設置的ConverterFactory進行serialization和deserialization,最后通過CallAdapter把結果進行進一步適配,實現了對Rxjava,Guava和java8的支持。
源碼剖析
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://www.baidu.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
retrofit.create(GitHub.class);
Retrofit實例是使用建造者模式通過Builder類進行創建的
建造者模式:將一個復雜對象的構建與表示分離,使得用戶在不知道對象的創建細節情況下就可以直接創建復雜的對象
Retrofit類
public final class Retrofit {
private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();
// 網絡請求配置對象(對網絡請求接口中方法注解進行解析后得到的對象)
// 作用:存儲網絡請求相關的配置,如網絡請求的方法、數據轉換器、網絡請求適配器、網絡請求工廠、基地
址等
private final HttpUrl baseUrl;
// 網絡請求的url地址
private final okhttp3.Call.Factory callFactory;
// 網絡請求器的工廠
// 作用:生產網絡請求器(Call)
// Retrofit是默認使用okhttp
private final List<CallAdapter.Factory> adapterFactories;
// 網絡請求適配器工廠的集合
// 作用:放置網絡請求適配器工廠
// 網絡請求適配器工廠作用:生產網絡請求適配器(CallAdapter)
// 下面會詳細說明
private final List<Converter.Factory> converterFactories;
// 數據轉換器工廠的集合
// 作用:放置數據轉換器工廠
// 數據轉換器工廠作用:生產數據轉換器(converter)
private final Executor callbackExecutor;
// 回調方法執行器
private final boolean validateEagerly;
// 標志位
// 作用:是否提前對業務接口中的注解進行驗證轉換的標志位
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)
// 作用:創建的新對象能夠對list數據進行訪問,但不可通過該對象對list集合中的元素進行修改
this.callbackExecutor = callbackExecutor;
this.validateEagerly = validateEagerly;
}
1、serviceMethod:包含所有網絡請求信息的對象
2、baseUrl:網絡請求的url地址
3、callFactory:網絡請求工廠
4、adapterFactories:網絡請求適配器工廠的集合
5、converterFactories:數據轉換器工廠的集合
6、callbackExecutor:回調方法執行器
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類的成員變量是對應的 所以Retrofit類的成員變量基本上是通過Builder類進行配置
Builder(Platform platform) {
//接收Platform對象(Android平臺)
this.platform = platform;
// 通過傳入BuiltInConverters()對象配置數據轉換器工廠(converterFactories)
// converterFactories是一個存放數據轉換器Converter.Factory的數組
// 配置converterFactories即配置里面的數據轉換器
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()方法。這里面的代碼,就是判斷當前運行的平臺。可以看到里面有Android、Java、IOS。
我們在Android上運行的話,就調用了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:返回的是用于執行 Callback 的 線程池。可以看到MainThreadExecutor 獲取了主線程的 Looper 并構造了一個主線程的 Handler,調用 Callback 時會將該請求 post 到主線程上去執行。這就解釋了為什么請求后完成的回調都是在主線中。
defaultCallAdapterFactory:將返回的適配類型默認為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;
}
這里有兩個重載的方法,創建了okhttp3 的 HttpUrl 實例。
addConverterFactory(GsonConverterFactory.create())
public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
往轉換工廠集合中添加了我們指定的轉換工廠,最后將返回的數據類型轉換成對應的實體類對象的Converter類型。在我們的例子里面 GsonConverterFactory 將選用 GsonConverter 來轉換。
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這里才是創建Retrofit對象的地方,之前的只是一些配置。里面的參數:
callFactory(Call工廠):看到了吧callFactory = new OkHttpClient();,這里用的是okhttp3;
baseUrl(服務器基本地址):這個我們上面配置過;
converterFactories(對象的序列號/反序列化組件):我們上面配置過。
adapterFactories(適配類型)、callbackExecutor(執行 Callback 的線程池):從我們上面提到的platform中獲取默認值。
Retrofit 2.0所使用的動態代理
Retrofit2.0用了動態代理技術,通過解析注解生成Http請求,把請求交給OkHttp,然后通過我們設置的ConverterFactory進行serialization和deserialization,最后通過CallAdapter把結果進行進一步適配,實現了對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);
//調用OkHttp,然后根據okHttpCall返回rxjava的Observe對象或者返回Call
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
這里的Platform 其實是檢測retrofit所運行的平臺,是java8還是android還是ios。這里主要是在builder的時候,如果沒有設置適配器,那么retrofit就會通過運行時的不同平臺,然后選擇不同的CallAdapterFactory。從上面的代碼可以看出,create 方法返回了一個動態代理對象,通過Github接口生成代理類,并將代理類的實現交給 InvocationHandler 作為具體的實現。這里使用動態代理的好處是簡化復雜的網絡請求和解析、封裝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的解析結果),存在的話跳過第二步;
2.method不存在的話就創建一個,然后添加到緩存中;
3.返回ServiceMethod 對像。
看一下OkHttpCall是如何請求和回調的
@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
,是我們外面傳進來的serviceMethod
來構造出來的okhttp3.Call,在這里通過用call.enqueue(...)
把請求交給okhttp的隊列中,然后再通過異步回調切換到主線程
總結
啊.....舒了一口氣,整個源碼使用大量的設計模式
- retrofit.builder 建造者模式
- Android extends Platform 適配器模式
- 各種...Factory 工廠模式
- 在Retrofit中提供了四種CallAdapterFactory: ExecutorCallAdapterFactory(默認)、GuavaCallAdapterFactory、Java8CallAdapterFactory、RxJavaCallAdapterFactory
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor)) 策略模式 - create(final Class<T> service) 代理模式
等等一系列的設計模式的組合,使得各個功能模塊高度解耦
本章主要說了一下Retrofit是如何構建的,通過動態代理技術,通過解析注解生成Http請求,把請求交給OkHttp隊列,然后在回調的這樣一個流程。
點贊加關注是給我最大的鼓勵!
相關文章閱讀
Android-設計模式