金三銀四速速臨近,準(zhǔn)備分析一下用了一段時(shí)日的Retrofit,本文分析Retrofit2.1.0版本,2.2.0最近新發(fā)布,據(jù)說支持RxJava2
(°?°)?
Ps:對所用的框架分析也是面試重要一環(huán)哦,知其然而知其所然是考察程序員潛力的重要一環(huán)(??????)??
介紹
Retrofit:大名鼎鼎的Square公司旗下的開源框架,是OkHttp的封裝版,完成了高度的解耦,非常的好用,尤其配合是RESTful風(fēng)格的服務(wù)端。
基本用法
//定義一個(gè)全局單例(推薦)
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("yourAPI/")
.client(new OkHttpClient())
.addConverterFactory(GsonConverterFactory.create())
.build();
//定義一個(gè)接口,里面存放方法
public interface API{
//注意這個(gè)Call不是OkHttp3的Call
@GET("users/search/{keyword}")
Call<List<UserBean>> searchUserList(@Path("keyword") String keyword);
}
API api= retrofit.create(API.class);
api.searchUserList("張三").省略
入口
在我們構(gòu)建了一個(gè)Retrofit實(shí)例后,調(diào)用了create方法,調(diào)用API接口中定義的方法后直接可以發(fā)起網(wǎng)絡(luò)請求,這是怎么實(shí)現(xiàn)的呢?那么,請聽下回分解。讓我們進(jìn)去瞧瞧。
public <T> T create(final Class<T> service) {
//判斷了傳入的service必須為interface,且不能實(shí)現(xiàn)其他接口
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 {
//如果調(diào)用的方法是Object的
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//默認(rèn)進(jìn)不來這個(gè)if
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//重點(diǎn)*具體執(zhí)行細(xì)節(jié)
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
可以看到這里運(yùn)用了Java的動態(tài)代理技術(shù),關(guān)于動態(tài)代理的詳細(xì)介紹,這篇寫的很詳細(xì)。
我們先來看執(zhí)行細(xì)節(jié)的第一句
第一句
ServiceMethod serviceMethod = loadServiceMethod(method);
看起來像是把我們在API中定義的方法searchUserList
封裝成了一個(gè)對象
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;
}
果然,這里還運(yùn)用了建造者模式和緩存來設(shè)計(jì),API中的同一個(gè)方法只會構(gòu)建一次,值得一提的是ServiceMethod的原注釋
Adapts an invocation of an interface method into an HTTP call
意思是一個(gè)接口方法對應(yīng)一個(gè)Http請求,及接下來讓我們來看看ServiceMethod的構(gòu)造器,都帶上了注釋,看官暫時(shí)不明白也沒關(guān)系,后面會一一講解清楚。反正這博文也沒人看(;?_?)
ServiceMethod(Builder<T> builder) {
//負(fù)責(zé)創(chuàng)建請求
this.callFactory = builder.retrofit.callFactory();
//負(fù)責(zé)將請求適配成API中的Call或者RxJava的Observable
this.callAdapter = builder.callAdapter;
//請求的baseUrl
this.baseUrl = builder.retrofit.baseUrl();
//響應(yīng)體的解析器,上文設(shè)置了Gson來解析成
this.responseConverter = builder.responseConverter;
//請求的方式,POST,GET。。。
this.httpMethod = builder.httpMethod;
//請求的相對路徑,API中定義的路徑
this.relativeUrl = builder.relativeUrl;
//請求報(bào)文頭
this.headers = builder.headers;
//請求報(bào)文類型
this.contentType = builder.contentType;
//是否帶有請求體
this.hasBody = builder.hasBody;
//是否表單請求
this.isFormEncoded = builder.isFormEncoded;
//是否是Multipart請求,一般用于傳輸文件
this.isMultipart = builder.isMultipart;
//數(shù)組,記錄請求中方法的參數(shù),@Path,@Query等等
this.parameterHandlers = builder.parameterHandlers;
}
我們前文在API中定義的一個(gè)方法searchUserList
的生辰八字(包括方法的注解信息)就被封裝到了ServiceMethod中了。
第二句
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
如果說第一句是乘客準(zhǔn)備好了身份證,那么第二句代碼就是購票上車的具體操作。
我們可以看到OkHttpCall
的內(nèi)部是實(shí)現(xiàn)了retrofit2
包下的Call<T>
,主要是一個(gè)同步方法execute
,一個(gè)異步方法enqueue
,
@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 {
//創(chuàng)建一個(gè)Call
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轉(zhuǎn)換
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();
}
}
});
}
@Override
public Response<T> execute() throws IOException {
okhttp3.Call call;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
if (creationFailure != null) {
if (creationFailure instanceof IOException) {
throw (IOException) creationFailure;
} else {
throw (RuntimeException) creationFailure;
}
}
call = rawCall;
if (call == null) {
try {
//創(chuàng)建一個(gè)Call
call = rawCall = createRawCall();
} catch (IOException | RuntimeException e) {
creationFailure = e;
throw e;
}
}
}
if (canceled) {
call.cancel();
}
//將Response轉(zhuǎn)換
return parseResponse(call.execute());
}
細(xì)心地讀者可能都發(fā)現(xiàn)了,在這2個(gè)方法中都調(diào)用了2個(gè)方法
一個(gè)是
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;
}
這個(gè)方法完成了如下幾步操作
1.將serviceMethod
(乘客身份信息)+args
(乘客選擇的列車座位)生成了一個(gè)okhttp3.Request
(列車票)
2.serviceMethod.callFactory.newCall(request)
上車
3.將call返回,通知上級乘客已經(jīng)就位
toRequest(args)
無非就是將參數(shù)構(gòu)建成一個(gè)okhttp3請求,略過~~這里注意,將request
轉(zhuǎn)換成okhttp3.Call
是通過callFactory
來完成的,callFactory
是okhttp3.Call
下的Factory
接口,默認(rèn)也就是自家的OkHttpClient
,也可以通過new Retrofit.Builder().client(yourClient)
來改變。
還有一個(gè)是
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
// Remove the body's source (the only stateful object) so we can pass the response along.
rawResponse = rawResponse.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
int code = rawResponse.code();
if (code < 200 || code >= 300) {
//Http錯(cuò)誤碼的情況
try {
// Buffer the entire body to avoid future I/O.
ResponseBody bufferedBody = Utils.buffer(rawBody);
return Response.error(bufferedBody, rawResponse);
} finally {
rawBody.close();
}
}
if (code == 204 || code == 205) {
//204-205時(shí)服務(wù)端不返回實(shí)體內(nèi)容
return Response.success(null, rawResponse);
}
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
//將從okhttp3來的response通過轉(zhuǎn)換再解析成數(shù)據(jù)實(shí)體T
T body = serviceMethod.toResponse(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
// If the underlying source threw an exception, propagate that rather than indicating it was
// a runtime exception.
catchingBody.throwIfCaught();
throw e;
}
}
在這里我們又見到了熟悉的serviceMethod.toResponse
,
這個(gè)方法內(nèi)部也是調(diào)用接口來實(shí)現(xiàn)的
T toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
}
接口的初始化這里
new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.build();
也就是說看官不喜歡Gson也可以選用Jackson以及自定義,在項(xiàng)目中一般都要自定義,這里先挖個(gè)坑,(`?ω?′)
那么我們花了不少的篇幅來講解乘客購票上車這個(gè)動作,畢竟上車了不是還會有驗(yàn)票嗎 手動滑稽
第三句
return serviceMethod.callAdapter.adapt(okHttpCall);
接下來我們來看動態(tài)代理的最后一句,也就是司機(jī)開車,哦不,發(fā)起請求
這里我們又見到了老熟人serviceMethod
,這里也是通過callAdapter
這個(gè)接口來發(fā)起請求的。
//我們也可以添加對RxJava的支持,安利一波
Retrofit retrofit = new Retrofit.Builder()
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
由于在Retrofit中支持的adapterFactories
是一個(gè)List類型,并且默認(rèn)會在List中添加一個(gè)默認(rèn)的ExecutorCallAdapterFactory
,這里我們先分析它的源碼
final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
final Executor callbackExecutor;
ExecutorCallAdapterFactory(Executor callbackExecutor) {
//傳入一個(gè)回調(diào) 調(diào)度器
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) {
//返回調(diào)度器的回調(diào)結(jié)果
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(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(ExecutorCallbackCall.this, new IOException("Canceled"));
} 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);
}
});
}
});
}
@Override public boolean isExecuted() {
return delegate.isExecuted();
}
@Override public Response<T> execute() throws IOException {
return delegate.execute();
}
@Override public void cancel() {
delegate.cancel();
}
@Override public boolean isCanceled() {
return delegate.isCanceled();
}
@SuppressWarnings("CloneDoesntCallSuperClone") // Performing deep clone.
@Override public Call<T> clone() {
return new ExecutorCallbackCall<>(callbackExecutor, delegate.clone());
}
@Override public Request request() {
return delegate.request();
}
}
}
短短100行代碼看官可能看的有點(diǎn)找不到北
在
Retrofit.Builder
中我們執(zhí)行最后的build()
時(shí),Retrofit已經(jīng)為我們準(zhǔn)備了默認(rèn)的調(diào)度器,也就是Handler,也就是說callbackExecutor.execute(Runnable)
這個(gè)方法就相當(dāng)于Handler post一個(gè)任務(wù)到主線程,那么剩下的也就是紙老虎了,細(xì)心的同學(xué)可能注意到了,ExecutorCallbackCall
其實(shí)就是一個(gè)裝飾者模式。那么我們就簡單的分析完了Retrofit的一部分源碼。
總結(jié)
筆者總結(jié)了一張精簡的本文閹割版,如有錯(cuò)誤,敬請指正。
對RxJavaAdapter的分析和其他的補(bǔ)充就放到下一篇了(??ω??)
Retrofit源碼分析(二)
“你們是世上的鹽。鹽若失了味,怎能叫它再咸呢?以后無用,不過丟在外面,被人踐踏了。你們是世上的光。城造在山上是不能隱藏的。人點(diǎn)燈,不放在斗底下,是放在燈臺上,就照亮一家的人。你們的光也當(dāng)這樣照在人前,叫他們看見你們的好行為,便將榮耀歸給你們在天上的父。” (馬太福音 5:13-16 和合本)