1. 閱讀引導
在分析 Retrofit 原始碼之前,你首先得理解動態代理模式,因為Retrofit是通過動態代理的方式進行統一網路請求介面類的處理。Retrofit的程式碼量並不大,只是對OkHttp進行了封裝,用更少的程式碼進行網路請求,明白動態代理模式之後,再看Retrofit網路請求處理流程就很清楚了。少量的程式碼使用大量的設計模式,所以Retrofit框架很值得我們去研究。
2. Retrofit基本使用
- 配置Retrofit物件(與OkHttp相同,採用Builder模式)
Retrofit retrofit = new Retrofit.Builder().baseUrl("xxxxx").build();
- 建立請求介面類
public interface NetworkInterface {
@GET("...")
Call<MyResponse> listRepos(); //不同的方法代表不同的網路請求,可以宣告請求方式(GET、POST..),請求頭Header引數,請求體資訊。
....
}
複製程式碼
- 建立介面類例項
NetworkInterface networkInterface = retrofit.create(NetworkInterface.class);
- 呼叫方法,請求實際的網路請求
Call<MyResponse> call = networkInterface.listRepos();
call.enqueue(new Callback<MyResponse>() { //與OkHttp不同,非同步請求會回撥到主執行緒
@Override
public void onResponse(Call<MyResponse> call, Response<MyResponse> response) { }
@Override
public void onFailure(Call<MyResponse> call, Throwable t) { }
});
複製程式碼
3. Retrofit流程圖
說明: Retrofit只存在一個CallFactory,但是存在多個CallAdapterFactory和ConvertFactory,針對不同的請求介面方法,Retrofit會通過其返回值,選擇特定的CallAdapterFactory和CovertFactory。
4. Retrofit原始碼分析
4.1 Retrofit建立過程
通過前面基本的使用程式碼可以看出,Retrofit的建立也是採用Builder設計模式,通過new Retrofit.Builder().build()。我們先看看new Retrofit.Builder()的初始化工作。
public static final class Builder {
...
public Builder() {
this(Platform.get());
}
Builder(Platform platform) {
converterFactories.add(new BuiltInConverters());
}
...
}
複製程式碼
通過Platform.get()獲取當前平臺物件Platform,然後呼叫它的另一個構造器,在這個構造器中,為ConvertFactory集合新增一個預設的ConvertFactory,不同的ConvertFactory產生的Convert對OkHttp網路請求返回的Response轉化處理不一樣,而預設ConvertFactory的Convert並沒有對Response做太多處理,獲得的資料依舊是Response物件。通過Builder.addConverterFactory(xxx)新增更多的ConvertFactory,比如xxx替換為GsonConverterFactory.create()新增GsonConvertFatory,它產生的GsonConvert就能將Response對映成JavaBean實體。
回到主流程,還是看看Platform.get()是如何處理的吧!
class Platform {
private static final Platform PLATFORM = findPlatform(); // 靜態工廠模式!
static Platform get() {
return PLATFORM;
}
private static Platform findPlatform() { // 識別當前平臺,如果是Android,就直接返回Android()物件例項
try {
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
...
static class Android extends Platform { // Platform的子類,Android平臺物件類
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) { // 獲取Android平臺的預設CallAdapterFactory物件
if (callbackExecutor == null) throw new AssertionError();
return new ExecutorCallAdapterFactory(callbackExecutor);
}
static class MainThreadExecutor implements Executor { // 獲取Android平臺的預設執行緒執行排程器,其實就是通過Handler用於執行緒切換。
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
}
複製程式碼
總結: 通過new Retrofit.Builder()為ConvertFactory集合中新增一個預設ConvertFactory,建立一個包含預設的CallAdapterFactory、Executor的Android平臺物件。注意,預設的ConvertFactory已經新增到了ConvertFactory集合中了,但是Android物件中的CallAdapterFactory並沒有加入到CallAdapterFactory集合中。
接著看new Retrofit.Builder().build()中的build()方法:
public Retrofit build() {
if (baseUrl == null) { // 強制需要通過.baseUrl("xxxxx")配置url
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient(); // 建立CallFactory用於生產Call物件,從這裡也可以看出Retrofit最終還是通過OkHttp傳送網路請求
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor(); // 獲取Android平臺物件中的預設Executor,裡面通過Handler進行執行緒切換,上面有講過!
}
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
// 此處將Android平臺物件中的CallAdapterFactory新增到Retrofit的CallAdapterFactory集合中.
// 注意同時將Executor也傳入到這個CallAdapterFactory中,那麼工廠生產出來的CallAdapter就也就具有執行緒切換的能力。
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly); // 通過Builder建立Retrofit,並將配置引數作為引數傳入
}
複製程式碼
再看看一下Retrofit的構造:
Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories,
@Nullable Executor callbackExecutor, boolean validateEagerly) {
this.callFactory = callFactory;
this.baseUrl = baseUrl;
this.converterFactories = unmodifiableList(converterFactories); // Defensive copy at call site.
this.adapterFactories = unmodifiableList(adapterFactories); // Defensive copy at call site.
this.callbackExecutor = callbackExecutor;
this.validateEagerly = validateEagerly;
}
複製程式碼
4.2 核心動態代理程式碼
NetworkInterface networkInterface = retrofit.create(NetworkInterface.class);
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service); // 1. 判斷網路請求介面類的合法性
if (validateEagerly) { // 2. 是否需要提前對 網路請求介面類 中的方法進行提前處理,即為介面中的每一個方法提前處理成 SeviceMethod(核心類)物件,並快取。
eagerlyValidateMethods(service);
}
// 3. 生成動態代理類
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 {
...
// 4. 將介面中的方法處理成serviceMethod。
ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args); // 5. 建立 OkHttpCall物件,傳入serviceMethod物件和呼叫方法實際引數。
return serviceMethod.callAdapter.adapt(okHttpCall); // 6. 將Call物件進行CallAdapter進行轉化( 比如RxCallAdapter將Call轉化為Observable ) 注意Call還沒有被執行,即沒有進行網路請求。
}
});
}
複製程式碼
總結: (一 ) retrofit.create(xx)方法中處理分三步:
-
- 判斷網路請求介面類的合法性
-
- 是否需要提前對 網路請求介面類 中的方法進行預處理
-
- 返回生成動態代理類
(二) 呼叫網路請求介面方法,動態代理類中的invoke()方法被執行,也處理也分三步:
-
- 將對應的執行方法轉化成ServiceMethod物件
-
- 建立OkHttpCall物件
- 3 OkHttpCall通過CallAdapter進行Call的轉化
4.3 呼叫介面方法
Call call = networkInterface.listRepos();
在通過上面的說明,當呼叫網路請求介面類方法時,就會呼叫invoke方法,傳入通過反射獲取Method和執行方法引數args,因為沒有呼叫call.execute()或call.enqueue(Callback),所以Call並沒有執行。接下來我們具體看看invoke方法體中三部曲吧!
-
- 將對應的執行方法轉化成ServiceMethod物件
ServiceMethod<?, ?> loadServiceMethod(Method method) {
ServiceMethod<?, ?> result = serviceMethodCache.get(method); // 先從快取中取,如果在之前分析的create()中validateEagerly = true 必然從快取中能取到。
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder<>(this, method).build(); // 根據Method建立ServiceMethod物件
serviceMethodCache.put(method, result); // 將建立的ServiceMethod進行快取
}
}
return result;
}
複製程式碼
接下來看看,ServiceMethod的建立!
ServiceMethodBuilder.class
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit; // 1. 將外觀類 Retrofit傳入
this.method = method;
this.methodAnnotations = method.getAnnotations(); // 2. 獲取方法上的註解(@GET @POST... )
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations(); // 3. 獲取引數註解(@Query ...)
}
public ServiceMethod build() {
callAdapter = createCallAdapter(); // 4. 獲取該方法對應的CallAdapter
responseType = callAdapter.responseType(); // 5. 獲取該方法的響應型別,比如Response或者自定義的JavaBean
...
responseConverter = createResponseConverter(); // 6. 根據上面獲取的響應型別獲取對應的Convert
for (Annotation annotation : methodAnnotations) { // 7. 解析第二步得到的方法註解
parseMethodAnnotation(annotation);
}
...
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
...
Annotation[] parameterAnnotations = parameterAnnotationsArray[p]; // 8. 解析第三步得到的引數註解
...
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
return new ServiceMethod<>(this); // 建立ServiceMethod物件
}
複製程式碼
之前有說過Retrofit中可以有多個ConvertFactory和CallAdapterFactory,通過上面的第4步和第6步獲取該Method對應的ConvertFactory和CallAdapterFactory。這兩種Factory的適配過程近乎一樣,所以這裡只做CallAdapterFactory的配對過程。
private CallAdapter<T, R> createCallAdapter() {
Type returnType = method.getGenericReturnType();
...
Annotation[] annotations = method.getAnnotations();
...
return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
}
複製程式碼
Retrofit.class
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {
// type: return 返回的型別,比如Call、Observable
...
int start = adapterFactories.indexOf(skipPast) + 1; // 用於做CallAdapterFactory跳過處理,預設start = 0
for (int i = start, count = adapterFactories.size(); i < count; i++) {
CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
...
}
複製程式碼
每一個CallAdapterFactory需要實現一個get(returnType,xxx)方法,如果能處理這個returnType就返回對應的CallAdapter物件。比如預設returnType為Call,那麼就被預設的CallAdapterFactory接受處理,這個CallAdapterFactory在Android平臺類中defaultCallAdapterFactory()獲得(4.1 Retrofit建立過程 有說明)
Android.class
@Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
if (callbackExecutor == null) throw new AssertionError();
return new ExecutorCallAdapterFactory(callbackExecutor);
}
複製程式碼
ExecutorCallAdapterFactory.class
final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
final Executor callbackExecutor;
ExecutorCallAdapterFactory(Executor callbackExecutor) {
this.callbackExecutor = callbackExecutor;
}
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call<Object> adapt(Call<Object> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
複製程式碼
總結: ServiceMethod通過Builder模式建立,包含了Retrofit物件,對執行的Method進行剖析,像方法註解、引數註解、引數型別、CallAdapter、ConvertAdapter,所以一個ServiceMethod物件包含了網路請求需要的所有資訊。
-
- 建立OkHttpCall物件
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
OkHttpCall.class
OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) { this.serviceMethod = serviceMethod; this.args = args; } 複製程式碼
- 3 OkHttpCall通過CallAdapter進行Call的轉化
serviceMethod.callAdapter.adapt(okHttpCall);
如果介面方法返回型別是Call的話,CallAdapter就是預設的CallAdaterFactory建立的CallAdapter,即ExecutorCallAdapterFactory類中get()方法返回的CallAdapter:
new CallAdapter<Object, Call<?>>() { @Override public Type responseType() { return responseType; } @Override public Call<Object> adapt(Call<Object> call) { return new ExecutorCallbackCall<>(callbackExecutor, call); } }; 複製程式碼
接著定位返回的CallAdapter中adapt()方法,最後返回了一個new ExecutorCallbackCall<>(callbackExecutor, call); 物件,代表serviceMethod.callAdapter.adapt(okHttpCall);的執行結束,並向外暴露一個ExecutorCallbackCall物件。
- 同步非同步網路請求
// 同步請求 call.execute(); // 非同步請求 call.enqueue(new Callback<MyResponse>() { //與OkHttp不同,非同步請求會回撥到主執行緒 @Override public void onResponse(Call<MyResponse> call, Response<MyResponse> response) { } @Override public void onFailure(Call<MyResponse> call, Throwable t) { } }); 複製程式碼
與同步相比,非同步相對來說複雜一點點,這裡只分析非同步,相信非同步看懂了,同步肯定不在話下。
ExecutorCallbackCall.class
@Override public void enqueue(final Callback<T> callback) { ... delegate.enqueue(new Callback<T>() { // delegate是由serviceMethod.callAdapter.adapt(okHttpCall); 傳入的,所以最終的網路請求還是通過OkHttpCall進行。 @Override public void onResponse(Call<T> call, final Response<T> response) { callbackExecutor.execute(new Runnable() { // callbackExecutor 是Android平臺物件類中的MainThreadExecutor 主要將執行緒切換到主執行緒 @Override public void run() { if (delegate.isCanceled()) { ... } else { callback.onResponse(ExecutorCallbackCall.this, response); } } }); } @Override public void onFailure(Call<T> call, final Throwable t) { callbackExecutor.execute(new Runnable() { @Override public void run() { callback.onFailure(ExecutorCallbackCall.this, t); } }); } }); } 複製程式碼
OkHttpCall.class
@Override public void enqueue(final Callback<T> callback) { ... call.enqueue(new okhttp3.Callback() { // 這個Call才是OKHttp中正宗的Call @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); } ... } 複製程式碼
5. Retrofit設計模式
- Builder模式
- 外觀模式
- 靜態工廠模式
- 動態工廠模式
- 介面卡模式
- 動態代理模式