綜述
Retrofit2的用法在Retrofit2.0使用詳解這篇文章中已經詳細介紹過了。那麼在這就來看一下Retrofit2它是如何實現的。Retrofit2中它的內部網絡請求是依賴於OKHttp,所以Retrofit2可以看做是對OKHttp的一次封裝,那麼下面就開看下Retrofit2是如何對OKHttp進行封裝的。
回顧Retrofit2的使用
在這裏首先來回顧一下Retrofit2的使用。對於Retrofit2的使用可以分爲三步。
首先,我們創建一個Java接口GitHubService來作爲Http請求接口。
public interface GitHubService {
@GET("repos/{owner}/{repo}/contributors")
Call<ResponseBody> contributorsBySimpleGetCall(@Path("owner") String owner,
@Path("repo") String repo);
}
然後我們需要創建一個Retrofit實例,並通過Retrofit對象創建一個GitHubService接口的實現。
Retrofit retrofit = new Retrofit.Builder()
//添加對RxJava的支持
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
//添加對Json轉換器的支持
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("https://api.github.com/")
.build();
GitHubService service = retrofit.create(GitHubService.class);
最後通過調用我們創建的接口便能夠向後臺發起請求。
Call<ResponseBody> call = service.contributorsBySimpleGetCall("square", "retrofit");
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
......
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
......
}
});
Retrofit2源碼分析
首先通過@GET來標識這個接口是一個GET請求。那麼看一下這個GET註解的定義。
package retrofit2.http;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import okhttp3.HttpUrl;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Documented
@Target(METHOD)
@Retention(RUNTIME)
public @interface GET {
String value() default "";
}
從註解中可以看出這個註解是對方法的聲明,並且在運行時VM依然保留註解。Java自定義註解在這裏就不在過多說明,可以參考 Java註解在Android中使用這篇文章。
下面就再來看一下是如何創建Retrofit對象的。對於Retrofit對象的創建採用的是Builder模式。那麼在這裏我們就來看一下這個Builder類。
public static final class Builder {
//對平臺的支持
private Platform platform;
//發起請求OKHttp3的Client工廠
private okhttp3.Call.Factory callFactory;
//OKHttp2的HttpUrl對象,也就是將我們傳入的baseUrl字符串包裝成HttpUrl
private HttpUrl baseUrl;
//轉換器工廠集合,retrofit可以插入多個轉化器,例如:Gson,Jackson等等
private List<Converter.Factory> converterFactories = new ArrayList<>();
//用於發起請求和接收響應的Call適配器工廠集合,
//Retrofit對RxJava的支持就是通過在該集合中添加RxJavaCallAdapterFactory,
//而RxJavaCallAdapterFactory正是繼承自CallAdapter.Factory
private List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
//Executor併發框架,用於對請求後響應結果的回調執行
private Executor callbackExecutor;
//是否需要立即生效
private boolean validateEagerly;
Builder(Platform platform) {
this.platform = platform;
// 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());
}
public Builder() {
this(Platform.get());
}
//對屬性的配置
......
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);
}
}
對於Retrofit中的屬性配置已經在註釋中進行說明。在這裏在對Platform進行一下介紹。我們可以看出通過Platform.get()來獲取到當前運行的平臺。下面就進出Platform.get()方法中來查看一下Retrofit到底支持哪些平臺。
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
try {
Class.forName("java.util.Optional");
return new Java8();
} catch (ClassNotFoundException ignored) {
}
try {
Class.forName("org.robovm.apple.foundation.NSObject");
return new IOS();
} catch (ClassNotFoundException ignored) {
}
return new Platform();
}
在Platform的get方法中實際上還是調用了findPlatform方法,通過findPlatform方法我們可以看出Retrofit支持三個平臺,它們分別是Android,Java8,IOS。這裏的IOS指的是RoboVM。RoboVM它是一種可以在iOS設備上運行Java應用程序的技術,這種技術主要還是用於在遊戲開發中。在這裏我們只討論在Android平臺中的使用。在獲取到當前平臺爲Android平臺之後返回一個Android對象,這個Android類是Platform中的一個靜態內部類,並且它繼承自Platform。下面就在來看一下這個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類中重寫了父類的defaultCallbackExecutor和defaultCallAdapterFactory方法。
對於defaultCallbackExecutor方法它所返回的一個Executor,從它的實現類MainThreadExecutor可以看出,實際上就是在主線中創建一個Handler對象,然後通過Handler的post方法將請求的結果回調到主線程中運行。而defaultCallAdapterFactory它是默認的Call適配器,它是一個ExecutorCallAdapterFactory對象,對於ExecutorCallAdapterFactory在後面會進行說明。
在這裏完成了對於Retrofit對象的創建以後,便通過Retrofit中的create方法創建一個我們請求接口的實現。下面就來看一下這個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);
}
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
private void eagerlyValidateMethods(Class<?> service) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
if (!platform.isDefaultMethod(method)) {
loadServiceMethod(method);
}
}
}
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;
}
在create方法中首先會進行判斷所傳入進來的Service是否是一個接口,當我們將validateEagerly屬性設爲true的時候,在我們調用create方法創建一個Service,就直接調用eagerlyValidateMethods方法。而eagerlyValidateMethods的作用是通過反射獲取我們創建service接口中所有的接口方法,然後根據接口方法和當前的retrofit對象來獲得ServiceMethod並且以接口方法作爲Key,ServiceMethod作爲值添加到serviceMethodCache緩存中。下次便可以通過接口方法直接獲取ServiceMethod。
現在在往下看我們就明白爲什麼通過接口來作爲一個Http請求,以及爲什麼調用create方法時需要驗證我們的service是否爲一個接口。因爲在這裏是通過Java的動態代理來實現Http請求,並返回一個代理類對象。對於Java的動態代理它是需要委託類與代理類實現同一個接口,在這裏也就是我們創建的service請求接口。對於Java的動態代理可參考Java設計模式之代理模式這篇文章。當我們通過代理類(也就是我們調用create方法後返回的service)調用我們所創建的接口方法時。InvocationHandler中的invoke方法將會被調用。在invoke方法中由於method.getDeclaringClass()獲取到的是一個接口,並不是Object類,所以第一個條件不成立。而在Android平臺下platform.isDefaultMethod(method)返回的爲false,所以這個條件也不成立。之後通過loadServiceMethod方法來獲取ServiceMethod。最後調用ServiceMethod中callAdapter的adapt方法。而ServiceMethod中的callAdapter屬性是通過ServiceMethod中createCallAdapter方法所創建。在createCallAdapter中實際上是調用了Retrofit中的callAdapter方法來對ServiceMethod中的callAdapter進行初始化。下面再看一下Retrofit中的callAdapter方法。
public CallAdapter<?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
checkNotNull(returnType, "returnType == null");
checkNotNull(annotations, "annotations == null");
int start = adapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = adapterFactories.size(); i < count; i++) {
CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
......
}
在這段代碼中,通過遍歷adapterFactories並根據我們的接口方法所中返回值類型來獲取響應的適配器callAdapter。例如上面的例子中返回值是一個Call對象,將會採用默認的適配器,如果我們返回的是RxJava中Observable對象,如果我們添加了RxJavaCallAdapterFactory,那麼返回的就是RxJavaCallAdapter。如果沒有添加那麼此處的adapter爲null,便會拋出異常。在正是通過這種適配器模式完成了對RxJava的完美結合。下面就以Retrofit默認的callAdapter爲例來看一下是如何調用OKHttp來完成對網絡的請求的。對於此時的callAdapter就是通過platform.defaultCallAdapterFactory(callbackExecutor)所創建的適配器。從剛纔觀察Platform內部類Android中可以看出它返回的是一個ExecutorCallAdapterFactory對象。下面就來看一下這個ExecutorCallAdapterFactory類。
final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
final Executor callbackExecutor;
ExecutorCallAdapterFactory(Executor callbackExecutor) {
this.callbackExecutor = callbackExecutor;
}
@Override
public CallAdapter<Call<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public <R> Call<R> adapt(Call<R> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@Override public void enqueue(final Callback<T> callback) {
if (callback == null) throw new NullPointerException("callback == null");
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(final Call<T> call, final Response<T> response) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
callback.onFailure(call, new IOException("Canceled"));
} else {
callback.onResponse(call, response);
}
}
});
}
@Override public void onFailure(final Call<T> call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(call, t);
}
});
}
});
}
......
}
從ExecutorCallAdapterFactory類中可看出通過get方法返回一個CallAdapter對象,從對CallAdapter的實現中可以看出在CallAdapter中的adapt方法返回的是ExecutorCallbackCall對象。它實現了Retrofit中的Call接口。到這裏我們也就明白了,當通過代理調用我們創建的接口方法中所返回的Call對象就是這個ExecutorCallbackCall。當我們通過call.enqueue來完成網絡請求操作實際上就是調用ExecutorCallbackCall中的enqueue方法。在ExecutorCallbackCall中enqueue又將網絡請求委託給OkHttpCall去執行。而這個OkHttpCall正是我們在Retrofit的create方法中所創建的OkHttpCall。由於OKHttp的CallBack接口中的onResponse和onFailure是在子線程中執行的,所以在這時候又通過callbackExecutor將CallBack的onResponse和onFailure切換到主線程中執行。
總結
在這裏對於Retrofit2的源碼分析就結束了,在這裏我們只分析了通過GET方式進行異步請求這一種情況,對於同步,以及POST請求等原理類似,在這就不在進行詳細說明。在Retrofit2中我們可以發現它的代碼雖然不多,但是卻大量用到了Java中的設計模式。很是值得我們學習。