Retrofit已經出來很多時間了,項目中也一直在用,只知道它的功能強大,不知其原理,這不是一個號的開發,所以最近一段時間把retrofit源碼研究了一下。我們先從它的功能說起。
retrofit功能
retrofit 是一個網絡情況框架,配合Okhttp進行網絡請求,但是retrofit本身實際是不參與網絡請求的過程,它只是根據我們接口定義的參數和配置,生成對應的網絡請求類(這個類默認是Httpclient)。
說完了功能,下面我們一點一點的來了解retrofit是怎樣的工作流程。
1. Retrofit的創建
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.build();
retrofit的創建是通過retrofit內部的builder來構建的,使用了建造者模式很好的將使用者和調用者分離開了。
retrofit.builder中的屬性很多,我們直接跳到build()方法看生產Retrofit
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<>(1 + this.converterFactories.size());
// 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);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
中間主要是對retrofit 中設置一些默認的屬性
- baseUrl:請求的base地址,不能為null,否則拋異常
- callFactory: 默認的網絡請求,okhttpclient
- callbackExecutor:通過Platform獲取到默認的請求線程調度器
- adapterFactories: 網絡請求類轉換器,默認添加了DefaultCallAdapterFactory
- converterFactories:網絡結果response轉化對象,默認添加了BuiltInConverters
簡單說下PlatForm
platform會更具不同的平臺處理不同的代碼,這里我們主要關注的是Android
static class Android extends Platform {
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
if (callbackExecutor == null) throw new AssertionError();
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);
}
}
}
可以留意到platform中提供兩個方法
- defaultCallbackExecutor()默認的調度器,用來指定,我們回調在哪個線程調用
- defaultCallAdapterFactory()默認的CallAdapterFactory(這個類主要是用來將retrofit2.call請求類型轉化為我們接口定義的類型轉換器),具體后面會說明
小結: 在retrofit創建的時候,已經初始化指定了一些默認參數
1. baseUrl:請求base地址
2. CallFactory: 網絡請求類 OkhttpClient
3. CallBackExcutor: 網絡返回調度器(默認是在主線程)
4. CallAdapterFactory: 網絡請求類轉換器(轉換我們接口中定義的請求網絡返回類型)
5. Convert: 默認返回response轉換器
好了,retrofit的創建基本已經分析完了,下面的自定義的接口實例的創建了。
2.自定義接口類型的創建
retrofit.create(Interface.class)進去看方法。
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, @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);
}
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
使用動態代理返回的是接口類的一個代理類,我們先不看代理類做了哪些額外的工作,先往下走流程,拿到代理類之后,該請求網絡了。
Call<List<Repo>> repos = service.listRepos("octocat");
repos.execute().body()
直接調用代理接口類中的方法,返回了一個網絡請求對象retrofit2.call
最后通過retrofit2.call.execute().body()返回請求結果
我們重點就在retrofit.create()生成接口代理類,以及接口代理類調用方法返回網絡請求對象的過程了。
invocationHandeler中的invoke主要如下:
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
第一步:通過loadServiceMethod()獲取ServiceMethod對象
ServiceMethod<?, ?> loadServiceMethod(Method method) {
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
先從緩存中獲取method方法,沒有,在創建一個新的放入緩存。
注意: serviceMethod 實際上就是對應的一個接口中請求方法,每一個方法只會創建一個,其余從緩存里取。
再來看看ServiceMethod.Builder和retrofit中的Builder一樣,都是使用了建造者模式方面使用者和調用者分離。
serviceMethod的創建是在build()方法中,主要是通過invok()中的方法,獲取方法中的參數和注解,生成相關的屬性:
更具接口定義主要獲取如下:
- CallAdapter:獲取定義接口中的網絡請求返回轉換類型
- responseConvert:獲取接口定義中返回response需要轉換的數據結構類型
- parameterHandlers: 通過解析注解得到注解中的參數,例如請求地址,請求參數等。
第二步創建一個OkhttpCall(retrofit2.call)
默認的具體實現網絡請求的對象,內部實現了retrofit.call接口,但內部真正使用的是okhttp3.call對象,這里使用了依賴倒置模式使得可以更好的擴展
內部,包含了enqueue()異步請求、execute同步請求、cancel、取消網絡請求等。
第三步通過callAdapter將返回類型的retrofit2.call轉化成我們接口定義的類型,例如observable<Object>、Flowable<Object>等
servicemethod會調用retrofit中的callAdapter,內部回去遍歷所有的callAdapterFactory去嘗試創建callAdapter,直到創建成功。
最后調用callAdapter中的adapter,將okhttpCall轉化為我們接口定義的返回類型。
好了,retrofit源碼的學習基本就到這里了。過程有點簡單,只是簡單的梳理了一下。