Retrofit的原始碼分析將從基本的使用方法入手,分析retrofit的實現方案,以及其中涉及到的一些有趣的技巧。並且建議大家也去github下載一份原始碼,跟著本文理一遍基本的流程。
簡單使用
定義HTTP API
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}複製程式碼
建立Retrofit並生成API的實現
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
GitHubService service = retrofit.create(GitHubService.class);複製程式碼
呼叫API方法,生成Call
Call<List<Repo>> repos = service.listRepos("octocat");複製程式碼
Retrofit的建立
retrofit例項的建立,使用了builder模式,從下面的原始碼中可以看出。
public static final class Builder {
Builder(Platform platform) {
this.platform = platform;
converterFactories.add(new BuiltInConverters());
}
public Builder() {
// Platform.get()方法可以用於判斷當前的環境
this(Platform.get());
}
public Builder baseUrl(String baseUrl) {
checkNotNull(baseUrl, "baseUrl == null");
HttpUrl httpUrl = HttpUrl.parse(baseUrl);
if (httpUrl == null) {
throw new IllegalArgumentException("Illegal URL: " + baseUrl);
}
return baseUrl(httpUrl);
}
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();// 新建Client,留到之後newCall什麼的
}
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);
}
}複製程式碼
這裡除了builder模式以外,還有兩個地方需要關注下,一個是Platform.get()
方法。它通過Class.forName
獲取類名的方式,來判斷當前的環境是否在Android中,這在之後獲取預設的CallAdapterFactory
時候將會用到,對這個方法感興趣的可以跟過去檢視下,這裡就不貼了。另一個是在build()
中建立了OkHttpClient
。
retrofit.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() {
// platform 可以分辨出你是在android,還是java8,又或者別的
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.
// 這裡的invoke,Object方法都走這裡,比如equals、toString、hashCode什麼的
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
// java8預設方法,1.8的新特性
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);
}
});
}複製程式碼
可以看出建立API使用了動態代理,根據介面動態生成的代理類,將介面的都轉發給了負責連線代理類和委託類的InvocationHandler
例項,介面方法也都通過其invoke
方法來處理。
在invoke
方法中,首先會通過Platform.get()
方法判斷出當前程式碼的執行環境,之後會先把Object
和Java8的預設方法進行一個處理,也是在進行後續處理之前進行去噪。其中的關鍵程式碼其實就是最後三句,這也是這篇文章將要分析的。
建立ServiceMethod
ServiceMethod<?, ?> loadServiceMethod(Method method) {
// 從快取裡面取出,如果有的話,直接返回好了
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
// 為null的話,解析方法的註解和返回型別、引數的註解he引數型別,新建一個ServiceMethod
result = new ServiceMethod.Builder<>(this, method).build();// ->
// 新建的ServiceMethod加到快取列表裡面
serviceMethodCache.put(method, result);
}
}
return result;
}複製程式碼
首先會嘗試根據方法從快取中取出ServiceMethod
例項,如果沒有,在鎖保護之後,還有再嘗試一次,還是沒有的情況下,才會去建立ServiceMethod
。ServiceMethod的建立於Retrofit類似,都是builder
模式。ServiceMethod建立的實際流程都放在了最後的build()
方法中。
public ServiceMethod build() {
callAdapter = createCallAdapter();// ->獲取CallAdapter的實現,一般為ExecutorCallAdapterFactory.get實現
responseType = callAdapter.responseType();
if (responseType == Response.class || responseType == okhttp3.Response.class) {
throw methodError("'"
+ Utils.getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
responseConverter = createResponseConverter();// 響應的轉換工廠,如GsonConverterFactory
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);// 真正解析方法註解的地方來了
}
if (httpMethod == null) {
throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
if (!hasBody) {// POST方法需要有body或者表單
if (isMultipart) {
throw methodError(
"Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
}
if (isFormEncoded) {
throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
+ "request body (e.g., @POST).");
}
}
// 上面是請求方法,下面是請求引數
int parameterCount = parameterAnnotationsArray.length;
// ParameterHandler的實現類有很多,包括了各種引數,@Field、@Query等
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];// 引數型別
// 和之前一樣的泛型、萬用字元檢查
if (Utils.hasUnresolvableType(parameterType)) {
throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
parameterType);
}
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];// 引數的註解集合
if (parameterAnnotations == null) {
throw parameterError(p, "No Retrofit annotation found.");
}
// 生成了對應的引數註解ParameterHandler例項
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
// 對方法的一些檢測
...
return new ServiceMethod<>(this);
}複製程式碼
可以看到在build方法中,對CallAdapter
與Converter
進行了建立,這裡跟蹤之後將會回到retrofit
類中,在其中將會獲取對應列表中的第一個!null物件,之後將會對API的方法和引數註解進行解析。
註解的解析
CallAdapter
和Converter
等到後面再分析,這裡先看看parseMethodAnnotation(annotation)
,功能和其名字一樣,其對方法註解進行了解析。
/**
* 解析方法註解,嗚啦啦
* 通過判斷註解型別來解析
* @param annotation
*/
private void parseMethodAnnotation(Annotation annotation) {
if (annotation instanceof DELETE) {
parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
} else if (annotation instanceof GET) {
parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
}
// 其他的一些方法註解的解析
...
}
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
if (this.httpMethod != null) {// 已經賦值過了
throw methodError("Only one HTTP method is allowed. Found: %s and %s.",
this.httpMethod, httpMethod);
}
this.httpMethod = httpMethod;
this.hasBody = hasBody;
// value為設定註解方法時候,設定的值,官方例子中的users/{user}/repos or user
if (value.isEmpty()) {
return;
}
// 查詢條件的一些判斷
...
this.relativeUrl = value;
this.relativeUrlParamNames = parsePathParameters(value);
}
`複製程式碼
在解析註解時,先通過instanceof
判斷出註解的型別,之後呼叫parseHttpMethodAndPath
方法解析註解引數值,並設定httpMethod、relativeUrl、relativeUrlParamNames
等屬性。
上面說了API中方法註解的解析,現在來看看方法引數註解的解析,這是通過呼叫parseParameterAnnotation
方法生成ParameterHandler例項來實現的,程式碼比較多,這裡挑選@Query來看看。
else if (annotation instanceof Query) {
Query query = (Query) annotation;
String name = query.value();
boolean encoded = query.encoded();
Class<?> rawParameterType = Utils.getRawType(type);// 返回基礎的類
gotQuery = true;
// 可以迭代,Collection
if (Iterable.class.isAssignableFrom(rawParameterType)) {
if (!(type instanceof ParameterizedType)) {
throw parameterError(p, rawParameterType.getSimpleName()
+ " must include generic type (e.g., "
+ rawParameterType.getSimpleName()
+ "<String>)");
}
ParameterizedType parameterizedType = (ParameterizedType) type;
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);// 返回基本型別
Converter<?, String> converter =
retrofit.stringConverter(iterableType, annotations);
return new ParameterHandler.Query<>(name, converter, encoded).iterable();
} else if (rawParameterType.isArray()) {// Array
Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());// 如果是基本型別,自動裝箱
Converter<?, String> converter =
retrofit.stringConverter(arrayComponentType, annotations);
return new ParameterHandler.Query<>(name, converter, encoded).array();
} else {// Other
Converter<?, String> converter =
retrofit.stringConverter(type, annotations);
return new ParameterHandler.Query<>(name, converter, encoded);
}複製程式碼
在@Query中,將分成Collection、array、other三種情況處理引數,之後根據這些引數,呼叫ParameterHandler中的Query靜態類,建立出一個ParameterHandler例項。這樣迴圈直到解析了所有的引數註解,組合成為全域性變數parameterHandlers,之後構建請求時會用到。
OkHttpCall
ServiceMethod
建立完成之後,我們來看看下一行程式碼中的OkHttpCall
類,裡面的包含了請求的執行和響應處理,我們來看看非同步請求的做法。
OkHttpCall(ServiceMethod<T, ?> serviceMethod, Object[] args) {
this.serviceMethod = serviceMethod;
this.args = args;
}
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "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 {
call = rawCall = createRawCall();// 建立OkHttp3.Call
} 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 = 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();
}
}
});
}
private okhttp3.Call createRawCall() throws IOException {
Request request = serviceMethod.toRequest(args);// 根據ParameterHandler組裝Request.Builder,生成Request
okhttp3.Call call = serviceMethod.callFactory.newCall(request);// Retrofit中建立的new OkHttpClient().newCall(request)
...
return call;
}複製程式碼
首先在建構函式中傳入了之前新建的serviceMethod
和動態代理invoke
方法傳遞來的args
引數。我們來看看其非同步方法enqueue
,將會呼叫createRawCall()
方法,跟進來可以看到,做了兩件事情,第一件事情,呼叫serviceMethod.toRequest
方法,創造出一個Request
物件,這個Request
物件就是根據之前提到的方法引數註解的集合parameterHandlers
建立的。第二件事是建立一個okhttp3.Call
物件,我們都知道Okhttp中建立這個物件的方法就是newCall,這和上面的程式碼如出一轍,那麼callFactory
引數是不是就是OkHttpClient
呢?bingo!確實如此,稍微跟蹤一下就可以發現,它的建立出現在Retrofit.Builder.build()
方法中,而引數就使用剛剛建立的request
物件,構成okhttp3.Call
,並返回。
CallAdapter
現在來看看enqueue
傳入的引數callback
,這個引數可能和很多人心中想的並不一樣,它並不是使用者在使用時傳入的那個Callback
物件。那麼他是從哪裡來的呢?不知道你還記不記得我之前在Retrofit.Builder.build()
方法中提到過一句程式碼Platform.get()
。在不使用addCallAdapterFactory
的情況下。將會使用Platform
的一種內部類,在Android環境下將會使用到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 {
// Looper.getMainLooper()就是為嘛響應會在主執行緒的原因
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}複製程式碼
上面的程式碼先稍微放一下,我們繼續看retrofit.Bulider.build
,其中有幾句比較關鍵的程式碼。
callFactory = new OkHttpClient();
callbackExecutor = platform.defaultCallbackExecutor();
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));複製程式碼
結合Android
類中的程式碼可以看出,其最後生成了ExecutorCallAdapterFactory
類。雖然看到了CallAdapter.Factory
,但是到底是哪裡執行了enqueue
方法呢?現在我們來看看retrofit.create
的最後一句程式碼serviceMethod.callAdapter.adapt(okHttpCall)
。
這裡的callAdapter
在不使用addCallAdapterFactory
的Android環境中,就是上面我們說到new ExecutorCallAdapterFactory
中get方法返回的物件。
@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) {// Retrofit動態代理serviceMethod.callAdapter.adapt(okHttpCall);呼叫到這裡
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}複製程式碼
responseType
方法返回的物件之後會在Converter
中用到,不過接下來先繼續看看其呼叫adapter
方法生成的ExecutorCallbackCall
物件。
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "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);
}
});
}
});
}複製程式碼
這裡的引數callback
才是使用者輸入的回撥物件,而其中的delegate
就是之前的okhttpCall
。所以delegate.enqueue
就是呼叫了OkhttpCall.enqueue
,而其中的callbackExecutor
就是剛剛的主執行緒。
順便再來看看常用的RxJava2CallAdapter,這裡直接從RxJava2CallAdapter.adapter
方法開始
@Override public Object adapt(Call<R> call) {
Observable<Response<R>> responseObservable = isAsync
? new CallEnqueueObservable<>(call)
: new CallExecuteObservable<>(call);
Observable<?> observable;
if (isResult) {
observable = new ResultObservable<>(responseObservable);
} else if (isBody) {
observable = new BodyObservable<>(responseObservable);
} else {
observable = responseObservable;
}
if (scheduler != null) {
observable = observable.subscribeOn(scheduler);
}
...
return observable;
}複製程式碼
adapter最終建立了Observable,主我們這裡分析其中開頭的兩步來:
- 分非同步和同步請求建立responseObservable
- 根據返回的型別建立observable
這裡以非同步為例,看看CallEnqueueObservable
類
final class CallEnqueueObservable<T> extends Observable<Response<T>> {
private final Call<T> originalCall;
CallEnqueueObservable(Call<T> originalCall) {
this.originalCall = originalCall;
}
@Override protected void subscribeActual(Observer<? super Response<T>> observer) {
// Since Call is a one-shot type, clone it for each new observer.
Call<T> call = originalCall.clone();
CallCallback<T> callback = new CallCallback<>(call, observer);
observer.onSubscribe(callback);
call.enqueue(callback);// 這裡執行了enqueue
}
private static final class CallCallback<T> implements Disposable, Callback<T> {
private final Call<?> call;
private final Observer<? super Response<T>> observer;
boolean terminated = false;
CallCallback(Call<?> call, Observer<? super Response<T>> observer) {
this.call = call;
this.observer = observer;
}
@Override public void onResponse(Call<T> call, Response<T> response) {
if (call.isCanceled()) return;
try {
observer.onNext(response);
if (!call.isCanceled()) {
terminated = true;
observer.onComplete();
}
} catch (Throwable t) {
...
}
}
@Override public void onFailure(Call<T> call, Throwable t) {
if (call.isCanceled()) return;
try {
observer.onError(t);
} catch (Throwable inner) {
Exceptions.throwIfFatal(inner);
RxJavaPlugins.onError(new CompositeException(t, inner));
}
}
...
}
}複製程式碼
在subscribeActual
方法內,主要做了三件事情:
- clone了原有的call,因為OkHttp.Call只能使用一次
- 設定了onSubscribe,可用於解除訂閱
- 執行了enqueue請求
再看看第二步,這裡以BodyObservable
為例子:
final class BodyObservable<T> extends Observable<T> {
private final Observable<Response<T>> upstream;
BodyObservable(Observable<Response<T>> upstream) {
this.upstream = upstream;
}
@Override protected void subscribeActual(Observer<? super T> observer) {
upstream.subscribe(new BodyObserver<T>(observer));
}
private static class BodyObserver<R> implements Observer<Response<R>> {
private final Observer<? super R> observer;
private boolean terminated;
BodyObserver(Observer<? super R> observer) {
this.observer = observer;
}
@Override public void onSubscribe(Disposable disposable) {
observer.onSubscribe(disposable);
}
@Override public void onNext(Response<R> response) {
if (response.isSuccessful()) {
observer.onNext(response.body());
} else {
...
observer.onError(t);
...
}
}
@Override public void onComplete() {
if (!terminated) {
observer.onComplete();
}
}
@Override public void onError(Throwable throwable) {
if (!terminated) {
observer.onError(throwable);
}
...
}
}
}複製程式碼
程式碼中的subscribeActual
方法在subscribe
之後執行,自然responseObservable
就訂閱了BodyObserver
,所以上面CallEnqueueObservable
中的CallCallback.onResponse
內,呼叫observer.onNext
也就是BodyObserver.onNext
,最後剛開始的觀察著就收到了response.body()
。
Converter
現在回到khttpCall.enqueue方法中,在其中還有一句重要的程式碼沒有看,那就是response = parseResponse(rawResponse);
,我們來看看這其中做了什麼。
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 th
rawResponse = rawResponse.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.conte
.build();
...
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
T body = serviceMethod.toResponse(catchingBody);// 解析body,比如Gson解析
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
// If the underlying source threw an exception, propagate that rather
// a runtime exception.
catchingBody.throwIfCaught();
throw e;
}
}
### ServiceMethod
R toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
}複製程式碼
可以看出parseResponse最終呼叫了Converter.convert
方法。這裡以常用的GsonConverterFactory為例。
# GsonConverterFactory
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonResponseBodyConverter<>(gson, adapter);
}
# GsonResponseBodyConverter
final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
private final Gson gson;
private final TypeAdapter<T> adapter;
GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
this.gson = gson;
this.adapter = adapter;
}
@Override public T convert(ResponseBody value) throws IOException {
JsonReader jsonReader = gson.newJsonReader(value.charStream());
try {
return adapter.read(jsonReader);
} finally {
value.close();
}
}
}複製程式碼
responseBodyConverter
方法中用到的type引數就是之前我在CallAdapter中提到的responseType
方法的返回值。生成adapter方法,用於convert
方法使用。OkHttpCall在這之後的程式碼就比較簡單了,通過回撥將轉換後得響應資料傳送出去即可。
總結
本文分析了Retrofit的執行流程,其實包含了Retrofit、ServiceMethod、OkHttpCall、CallAdapter、Converter等方面。Retrofit的程式碼相對是比較少,也比較容易理解的,不過卻是很好的架構例項。
如果想看retrofit中其他一些程式碼的註釋,請點選這裡,如果其中發現不合適的描述,歡迎指出
如果在閱讀過程中,有任何疑問與問題,歡迎與我聯絡。
部落格:www.idtkm.com
GitHub:github.com/Idtk
微博:weibo.com/Idtk
郵箱:IdtkMa@gmail.com