【Android】Retrofit源碼學習
使用Retrofit的流程#
通過Builder創建Retrofit對象:
Copy
Retrofit retrofit = new Retrofit.Builder().baseUrl("").addConverterFactory().build();
用Java註解描述API
Copy
public interface MyApi {
@GET("/api")
Call<Data> getData();
}
通過retrofit創建api對象,並建立Call對象
Copy
MyApi api = retrofit.create(MyApi.class);
Call call = api.getData();
通過Call對象獲取數據,enqueue()方法發送異步請求,同步方式則使用execute()方法
Copy
call.enqueue(new Callback() {
@Override
public void onResponse(Response<ZhuanLanAuthor> author) {
System.out.println("name: " + author.getName());
}
@Override
public void onFailure(Throwable t) {
}
});
原理解析#
Retrofit所做的事情:將Java接口翻譯成HTTP請求,然後用OkHttp去發送請求。
Retrofit使用動態代理實現了這件事
動態代理#
動態代理可以在不實現相同接口的proxy的情況下,對相關方法進行代理。
Java可以通過Proxy類實現代理模式,而其中的newProxyInstance()方法可以實現動態代理。通過實現InvocationHandler接口來定義代理動作。
Proxy.newProxyInstance(ClassLoader, Class<?>[] interfaces,InvocationHandler)
InvocationHandler的接口定義如下:
Copy
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
參數含義:
proxy:代理對象
method: 代理方法
args: 方法的參數
實現invoke()方法來進行代理:
Copy
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// do something
method.invoke(target, args);
// do something
}
這樣便能夠成功對target方法進行代理,動態代理生成的代理類的名字爲包名+$Proxy+id序號
請求流程分析#
回到使用方法,一開始要使用create()生成API的對象
Copy
MyApi api = retrofit.create(MyApi.class);
這裏看下create()的源碼:
Copy
public T create(final Class service) {
validateServiceInterface(service); // 判斷是否爲接口
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
@Override public @Nullable Object invoke(Object proxy, Method method,
@Nullable Object[] args) throws Throwable {
// 如果是Object的方法則直接調用
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
// 兼容Java8,Android平臺不會調用, 確認平臺的方法是通過反射機制判斷類的加載信息
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
// 主要方法,返回ServiceMethod對象
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
create使用了動態代理的方法,返回了Proxy.newProxyInstance()動態代理對象
所以api對象爲動態代理對象,不是真正的實現接口產生的對象。當api對象調用getData()方法時會被動態代理攔截,然後調用InvocationHandler對象中的invoke()方法。
然後Retrofit通過反射獲取到getData()方法的註解信息,配合invoke()的args參數,創建一個ServiceMethod對象
ServiceMethod傳入Retrofit對象和Method對象,調用各個接口和解析器,最終生成一個Request,包含api的域名、path、http請求方法、請求頭、body等等。最後返回一個Call對象。
Copy
ServiceMethod<?> loadServiceMethod(Method method) {
ServiceMethod<?> result = serviceMethodCache.get(method); // 如果有緩存則直接用
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method); // 線程安全,鎖住後查看其他線程是否有加載
if (result == null) {
result = ServiceMethod.parseAnnotations(this, method); // 解析註解
serviceMethodCache.put(method, result); // 放入Cache中
}
}
return result;
}
跟進ServiceMethod.parseAnnotation():
Copy
static ServiceMethod parseAnnotations(Retrofit retrofit, Method method) {
// 解析註解爲HTTP請求的相關信息
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(method,
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) { //API接口方法返回值不能爲void
throw methodError(method, "Service methods cannot return void.");
}
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
這裏構建了一個RequestFactory對象,解析了接口中關於Http協議的相關信息,具體解析方法就是拿到Method的Annotation後instansof比較確定
Copy
RequestFactory(Builder builder) {
method = builder.method;
baseUrl = builder.retrofit.baseUrl;
httpMethod = builder.httpMethod;
relativeUrl = builder.relativeUrl;
headers = builder.headers;
contentType = builder.contentType;
hasBody = builder.hasBody;
isFormEncoded = builder.isFormEncoded;
isMultipart = builder.isMultipart;
parameterHandlers = builder.parameterHandlers;
isKotlinSuspendFunction = builder.isKotlinSuspendFunction;
}
解析完後使用HttpServiceMethod.parseAnnotations()最後生成HttpServiceMethod對象
Copy
static HttpServiceMethod parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction; // kotlin支持,先忽略
boolean continuationWantsResponse = false;
boolean continuationBodyNullable = false;
Annotation[] annotations = method.getAnnotations(); // 方法的註解 @GET @POST @DELETE等
Type adapterType;
// ...這裏有一段關於Kotlin支持的代碼,adapterType
adapterType = method.getGenericReturnType(); // 接口方法的返回類型,一般爲Call<T>
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
Type responseType = callAdapter.responseType();
if (responseType == okhttp3.Response.class) {
throw methodError(method, "'"
+ getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
if (responseType == Response.class) {
throw methodError(method, "Response must include generic type (e.g., Response<String>)");
}
// HEAD請求沒有Response Body
if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
throw methodError(method, "HEAD method must use Void as response type.");
}
// 設置Response的解析,可以是json解析
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory; // 這裏若是沒有自定則默認爲OkHttpClient
if (!isKotlinSuspendFunction) {
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter); // 不使用Kotlin就關注這裏就行了
}
// ...關於Kotlin的return
}
最後返回了HttpServiceMethod的繼承類CallAdapted,其中存放着RequestFactory、Converter、CallFactory
然後我們返回來看這段代碼
Copy
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
這裏調用的invoke方法來爲HttpServiceMethod中的invoke方法:
Copy
@Override final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
// CallAdapted中
@Override protected ReturnT adapt(Call call, Object[] args) {
return callAdapter.adapt(call);
}
這裏的OKHttpCall爲Okhttp3.Call的封裝類,並實現了Call的相關方法enqueue、execute。
這裏最後使用的adapt方法調用了Retrofit對象中的callAdapter.adapt()來對Call對象進行了適配。
若是開始初始化Retrofit對象時沒有設置CallAdapter,則回默認使用Call,api接口定義時方法的返回類型只能是Call
所以便能解釋如下代碼:
Copy
Call call = api.getData();
api對象爲一個動態代理對象,當執行getData()時進入動態代理函數,在InvocationHandler的invoke函數最後調用了HttpServiceMethod.invoke(args),返回了一個Call對象。
響應流程分析#
Retrofit使用中最後調用自定義的API接口方法返回了Call對象,這個對象實際上是Retrofit自己封裝的OkHttpCall對象,隨後我們使用enqueue方法發出異步請求
Copy
call.enqueue(new CallBack() {
@Override
public void onResponse(Call<MyData> call, Response<MyData> response) {
//... on response
}
@Override
public void onFailure(Call<MyData> call, Throwable t) {
//... on response
}
})
跟進OkHttpCall.enqueue的源碼:
Copy
@Override public void enqueue(final Callback callback) {
Objects.requireNonNull(callback, "callback == null"); // callback不能爲null
okhttp3.Call call; // okhttp3的Call對象
Throwable failure;
synchronized (this) { // 線程安全
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
call = rawCall; // rawCall爲OkHttpCall保存的Okttp3的Call對象
failure = creationFailure;
if (call == null && failure == null) {
try {
// createRawCall中使用callFactory.newCall(requestFactory.create(args))
// 實際上就是OkHttpClient.newCall(OkHttp3.Request)
// 返回了OkHttp3.Call對象
call = rawCall = createRawCall();
} catch (Throwable t) {
throwIfFatal(t);
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
// 使用okhttp3.Call的enqueue方法
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
// 這裏使用了Converter來解析Response
// 將Okhttp3.Response對象解析成Retrofit封裝的Response對象
response = parseResponse(rawResponse);
} catch (Throwable e) {
throwIfFatal(e);
callFailure(e);
return;
}
try {
// 調用傳進來的回調
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
throwIfFatal(t);
t.printStackTrace();
}
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}
// 請求失敗則進入callback的OnFailure方法
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
throwIfFatal(t);
t.printStackTrace();
}
}
});
}
其中parseResponse()方法:
Copy
Response parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
// 將Response Body 和 ResponseHeader 分開
// 之後再對Body進行處理
rawResponse = rawResponse.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
int code = rawResponse.code(); // HTTP 狀態碼
// 響應不成功
if (code < 200 || code >= 300) {
try {
// Buffer the entire body to avoid future I/O.
ResponseBody bufferedBody = Utils.buffer(rawBody);
return Response.error(bufferedBody, rawResponse);
} finally {
rawBody.close();
}
}
// 響應無內容,填入null
if (code == 204 || code == 205) {
rawBody.close();
return Response.success(null, rawResponse);
}
// 保存source的Response Body,在解析失敗時可以使用
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try {
// 使用responseConverter來解析Body
T body = responseConverter.convert(catchingBody);
// 將解析好的Body裝入Retrofit的Response對象返回
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
catchingBody.throwIfCaught();
throw e;
}
}
主要的parse過程便是,將Okhttp.Response對象的Body和Header拆開,若請求成功且Body有內容則將Body交給responseConverter取解析成響應對象,裝入Retrofit的Response對象中返回。
總結#
Retrofit的特色:通過使用註解定義API接口的方式聲明API,通過註解的解析,將解析得到的信息封裝在RequestFactory中,在使用時調用create()方法生成Okhttp的Request對象。
通過動態代理的方式,代理用戶定義的API接口方法,使其生成封裝的OkHttpCall對象
封裝okhttp.Call爲OkHttpCall,使其能夠使用CallAdapter(可以使返回的Call對象適配爲其他的對象,如RxJava(沒用過)中的對象)和ResponseConverter(支持Gson等解析)
目前只讀到這裏,還有一些機制沒讀完
參考文章#
https://www.jianshu.com/p/c1a3a881a144
https://segmentfault.com/a/1190000006767113
https://yq.aliyun.com/articles/658544
作者: y4ngyy