Retrofit2原始碼解析
最近專案將網路框架換成Retrofit2.0.2,文中說的Retrofit都是指的Retrofit2這裡要說明一下,畢竟和Retrofit1差別還是蠻大的,結合Okhttp,RxJava還是比較好用的,網上有很多前輩介紹過使用方法,本文是想研究一下Retrofit的原始碼。關於Retrofit的介紹可以查閱Retrofit的官方網站
直接進入主題:(注本文是結合RxJava介紹的,最好可以瞭解一下RxJava不瞭解也沒有關係,大部分的思想是一樣的)
Retrofit的基本使用
Retrofit使用是非常簡單的,在上邊的官網上介紹的也非常詳細。但是為了後邊的分析,還是把使用的程式碼貼在這兒:
一般在專案中會將需要請求網路方法寫在一個介面中,如下:
public interface GitHubService {
@GET("users/{user}/repos")
Observable<List<Repo>> listRepos(@Path("user") String user);
}
如果要使用Retrofit還需要構建Retrofit的物件:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
主要就是配置baseUrl,ConverterFactory,CallAdapterFactory。這裡用的是Gson,和RxJava所以相應的就是GsonConverterFactory,RxJavaCallAdaperFactory這個在後邊的原始碼分析中會用到。
最後直接呼叫就可以了:
GitHubService service = retrofit.create(GitHubService.class);
service.listRepos("octocat")
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(list->{
if(list!=null){
//TODO 取得資料後邏輯處理
}
});
可以說,程式碼還是非常簡潔的。用起來也很容易上手。
Retrofit工作流程
如上面的使用中我們可以看到:
1.通過Retrofit.Builder().build()構建Retrofit例項。
2.呼叫Retrofit的create()方法將生成介面GitHubService的例項。
3.呼叫GitHubService的listRepos()方法返回Observable<List<Repo>>
,這裡的GitHubService例項實際上是個代理物件,這個下文再說。
下圖是我整理的Retrofit執行時主要節點的時序圖,當然不是所有的過程都反映出來了。
看不懂沒關係,一步一步來,先看看Retrofit原始碼的構成:

簡單的介紹一下
1.Call(介面)–向伺服器傳送請求並返回響應的呼叫
2.CallAdapter(介面)–Call的介面卡,用來包裝轉換Call
3.CallAdapter.Factory(介面)–CallAdapter的工廠,通過get方法獲取對應的CallAdapter
4.CallBack(介面)–Call的回撥
5.Converter(介面)–資料轉換器,將一個物件轉化另外一個物件
6.Converter.Factory(抽象類) – 資料轉換器Converter的工廠
responseBodyConverter – 將伺服器返回的資料轉化ResponseBody。
requestBodyConverter – 將GitHubService.listRepos()中的Body,Part等註解轉換為RequestBody(),以便Okhttp請求的時候使用。
stringConverter – 將Field,FieldMap 值,Header,Path,Query,和QueryMap值轉化為String,以便Okhttp請求的時候使用。
7.ServiceMethod 通過解析註解,傳參,會將你的介面方法呼叫轉化為一個 Call 物件。也就說對於每一個介面方法,他都會建立一個與之對應的 ServiceMethod
另外retrofit還有一個http包,都是用來定義 HTTP 請求的自定義註解。如果對註解不太熟悉可以看看我的ButterKnife原始碼剖析 關於註解的介紹。

回到上邊步驟2,呼叫Retrofit的create()方法將生成介面GitHubService的例項:
GitHubService service = retrofit.create(GitHubService.class);
將GithubService.class作為引數,傳入create(),然後又返回一個GithubService例項,看起來是不是很神奇。原始碼如下:
@SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
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);
}
});
}
這裡使用了動態代理,返回了一個 Proxy 代理類,呼叫GithubService(在自己的專案中是XXXService介面)介面中的任何方法都會呼叫 proxy 裡的 invoke 方法。這個方法裡邊最重要的就是第23,24,25行程式碼。
1.構建ServiceMethod例項
先看第23行
ServiceMethod serviceMethod = loadServiceMethod(method);
通過loadServiceMethod方法獲取ServiceMethod例項:
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;
}
第4行首先會先嚐試從serviceMethodCache(型別Map<Method, ServiceMethod>
)中get,如果快取中沒有則構建一個ServiceMethod例項。接著看怎麼構建ServiceMethod例項,ServiceMethod.java中原始碼:
public Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
public ServiceMethod build() {
callAdapter = createCallAdapter();
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();
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
if (httpMethod == null) {
throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
if (!hasBody) {
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;
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.");
}
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
if (relativeUrl == null && !gotUrl) {
throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
}
if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
throw methodError("Non-body HTTP method cannot contain @Body.");
}
if (isFormEncoded && !gotField) {
throw methodError("Form-encoded method must contain at least one @Field.");
}
if (isMultipart && !gotPart) {
throw methodError("Multipart method must contain at least one @Part.");
}
return new ServiceMethod<>(this);
}
使用Builder模式來構建serviceMethod例項,將retrofit例項,和invoke的方法作為引數來初始化。第10行通過呼叫createCallAdapter()建立CallAdapter例項callAdapter。
private CallAdapter<?> createCallAdapter() {
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError("Service methods cannot return void.");
}
Annotation[] annotations = method.getAnnotations();
try {
return retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create call adapter for %s", returnType);
}
}
看第11行,獲取到了,介面方法中使用的註解,在我們本文中的GithubService的listRepos的註解就是@Get();第13行會通過呼叫Retrofit的callAdapter()方法來返回CallAdapter例項:
Retrofit.java檔案中:
/**
* Returns the {@link CallAdapter} for {@code returnType} from the available {@linkplain
* #callAdapterFactories() factories}.
*
* @throws IllegalArgumentException if no call adapter available for {@code type}.
*/
public CallAdapter<?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
/**
* Returns the {@link CallAdapter} for {@code returnType} from the available {@linkplain
* #callAdapterFactories() factories} except {@code skipPast}.
*
* @throws IllegalArgumentException if no call adapter available for {@code type}.
*/
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;
}
}
StringBuilder builder = new StringBuilder("Could not locate call adapter for ")
.append(returnType)
.append(".\n");
if (skipPast != null) {
builder.append(" Skipped:");
for (int i = 0; i < start; i++) {
builder.append("\n * ").append(adapterFactories.get(i).getClass().getName());
}
builder.append('\n');
}
builder.append(" Tried:");
for (int i = start, count = adapterFactories.size(); i < count; i++) {
builder.append("\n * ").append(adapterFactories.get(i).getClass().getName());
}
throw new IllegalArgumentException(builder.toString());
}
真的實現是在Retrofit.java中的nextCallAdapter()方法中實現的。上邊程式碼第25行,adapterFactories是一個快取CallAdapter.Factory的list,我們在構建Retrofit例項時,曾經設定過addCallAdapterFactory(RxJavaCallAdapterFactory.create()),也就意味著adapterFactories.get(i)將獲得到RxJavaCallAdapterFactory,然後會執行其get()方法。
RxJavaCallAdapterFactory.java檔案中:
@Override
public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
Class<?> rawType = getRawType(returnType);
String canonicalName = rawType.getCanonicalName();
boolean isSingle = "rx.Single".equals(canonicalName);
boolean isCompletable = "rx.Completable".equals(canonicalName);
if (rawType != Observable.class && !isSingle && !isCompletable) {
return null;
}
if (!isCompletable && !(returnType instanceof ParameterizedType)) {
String name = isSingle ? "Single" : "Observable";
throw new IllegalStateException(name + " return type must be parameterized"
+ " as " + name + "<Foo> or " + name + "<? extends Foo>");
}
if (isCompletable) {
// Add Completable-converter wrapper from a separate class. This defers classloading such that
// regular Observable operation can be leveraged without relying on this unstable RxJava API.
// Note that this has to be done separately since Completable doesn't have a parametrized
// type.
return CompletableHelper.createCallAdapter(scheduler);
}
CallAdapter<Observable<?>> callAdapter = getCallAdapter(returnType, scheduler);
if (isSingle) {
// Add Single-converter wrapper from a separate class. This defers classloading such that
// regular Observable operation can be leveraged without relying on this unstable RxJava API.
return SingleHelper.makeSingle(callAdapter);
}
return callAdapter;
}
正常情況下,會執行到第27行,通過getCallAdapter方法,獲得Observable泛型的CallAdapter,繼續跟進去看看:
private CallAdapter<Observable<?>> getCallAdapter(Type returnType, Scheduler scheduler) {
Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType);
Class<?> rawObservableType = getRawType(observableType);
if (rawObservableType == Response.class) {
if (!(observableType instanceof ParameterizedType)) {
throw new IllegalStateException("Response must be parameterized"
+ " as Response<Foo> or Response<? extends Foo>");
}
Type responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
return new ResponseCallAdapter(responseType, scheduler);
}
if (rawObservableType == Result.class) {
if (!(observableType instanceof ParameterizedType)) {
throw new IllegalStateException("Result must be parameterized"
+ " as Result<Foo> or Result<? extends Foo>");
}
Type responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
return new ResultCallAdapter(responseType, scheduler);
}
return new SimpleCallAdapter(observableType, scheduler);
}
第3行會getRawType(observableType)會返回Observable具體型別,例如本例中,
public interface GitHubService {
@GET("users/{user}/repos")
Observable<List<Repo>> listRepos(@Path("user") String user);
}
返回值是Observable<List<Repo>>
那麼getRawType(observableType)將得到List.class,這樣程式將執行第22行,將返回一個SimpleCallAdapter例項,那麼它就是CallAdapter的真正實現。
回到ServiceMethod的build()方法中,繼續執行第18行responseConverter = createResponseConverter();過程也和createCallAdapter差不多,也是使用工廠模式,通過get()方法獲得Converter的真正實現,篇幅所限就不一步一步的跟了,本例使用的是Gson,所以Converter得實現是GsonResponseBodyConverter。之後就是解析註解,引數等,這樣ServiceMethod已經構建好了。
生成OkHttpCall
回到Retrofit動態代理invoke方法中,第二步就是生成Call的例項了,目前Retrofit的預設使用的是OkhttpCall。其是OkHttp的包裝類,所有OkHttp需要的引數都在該類中找到。
adapt Call
第三步執行serviceMethod.callAdapter.adapt(okHttpCall),通過之前的分析,serviceMethod.callAdapter真正的實現是SimpleCallAdapter,那麼自然也是執行的它的adapt()方法。為了證實這個,可以debug一下就知道了。
RxJavaCallAdapterFactory.SimpleCallAdapter.adapt():
@Override public <R> Observable<R> adapt(Call<R> call) {
Observable<R> observable = Observable.create(new CallOnSubscribe<>(call))
.lift(OperatorMapResponseToBodyOrError.<R>instance());
if (scheduler != null) {
return observable.subscribeOn(scheduler);
}
return observable;
}
}
其返回型別Observable,也就是我們需要的結果,還記得我們是怎麼使用的RxJava的嗎?
service.listRepos("octocat")
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(list->{
if(list!=null){
//TODO 取得資料後邏輯處理
}
});
看程式碼service.listRepos(“octocat”)應該是一個Observable,而剛剛分析的,service.listRepos(“octocat”)確實會返回一個Observable,有了這個Observable之後,我們就可以通過subscribeOn給他指定執行執行緒,這樣像網路請求耗時操作就不會再UI執行緒中執行,從而達到非同步的目的,然後通過observeOn()將執行緒切回UI執行緒,當Okhttp請求完資料並進行相應的convert之後,就可以在UI處理相應的邏輯。
回到adapt方法,第2行建立Observable,而new CallOnSubscribe<>(call)生成了一個OnSubscribe()的例項,而OnSubscribe繼承自Action1,其只包含一個call()方法,而這個call是在CallOnSubscribe中實現:
static final class CallOnSubscribe<T> implements Observable.OnSubscribe<Response<T>> {
private final Call<T> originalCall;
CallOnSubscribe(Call<T> originalCall) {
this.originalCall = originalCall;
}
@Override public void call(final Subscriber<? super Response<T>> subscriber) {
// Since Call is a one-shot type, clone it for each new subscriber.
Call<T> call = originalCall.clone();
// Wrap the call in a helper which handles both unsubscription and backpressure.
RequestArbiter<T> requestArbiter = new RequestArbiter<>(call, subscriber);
subscriber.add(requestArbiter);
subscriber.setProducer(requestArbiter);
}
}
首先clone了一份Call,然後生成了RequestArbiter,他繼承自AtomicBoolean,實現了Subscription, Producer介面,Producer只有一個request方法;一般實現該介面的類,都會包含一個Subscriber物件和一個待處理的資料:
static final class RequestArbiter<T> extends AtomicBoolean implements Subscription, Producer {
private final Call<T> call;
private final Subscriber<? super Response<T>> subscriber;
RequestArbiter(Call<T> call, Subscriber<? super Response<T>> subscriber) {
this.call = call;
this.subscriber = subscriber;
}
@Override public void request(long n) {
if (n < 0) throw new IllegalArgumentException("n < 0: " + n);
if (n == 0) return; // Nothing to do when requesting 0.
if (!compareAndSet(false, true)) return; // Request was already triggered.
try {
Response<T> response = call.execute();
if (!subscriber.isUnsubscribed()) {
subscriber.onNext(response);
}
} catch (Throwable t) {
Exceptions.throwIfFatal(t);
if (!subscriber.isUnsubscribed()) {
subscriber.onError(t);
}
return;
}
if (!subscriber.isUnsubscribed()) {
subscriber.onCompleted();
}
}
@Override public void unsubscribe() {
call.cancel();
}
@Override public boolean isUnsubscribed() {
return call.isCanceled();
}
}
那麼看看request()方法到底幹了什麼?第16行程式碼call.execute()最終將執行okhttp的execute(),為什麼這裡會同步請求資料呢,還記得之前我們把耗時操作切換到子執行緒中嗎?既然已經不是在UI執行緒了,這裡就可以使用同步獲取response資料了。在獲取到response後就通過執行subscriber.onNext(response);這樣subscribe過Observable的subscriber都可以收到資料了。而因為我們設定過observeOn(AndroidSchedulers.mainThread()),所以當我們接受到資料的時候,已經是在UI執行緒中了,所以就可以做後續的邏輯處理了。
總結:Retrofit 的程式碼並不是很多,其底層網路通訊時交由 OkHttp 3來完成的,但是Retrofit運用了大量的設計模式,程式碼邏輯很清晰。沒事的時候,不妨研究研究,畢竟是Jake Wharton大神的傑作。
相關文章
- Retrofit2原始碼解析(一)原始碼
- 【原始碼SOLO】Retrofit2原始碼解析(一)原始碼
- Java Timer原始碼解析(定時器原始碼解析)Java原始碼定時器
- 【原始碼解析】- ArrayList原始碼解析,絕對詳細原始碼
- ReactNative原始碼解析-初識原始碼React原始碼
- Koa 原始碼解析原始碼
- Koa原始碼解析原始碼
- RxPermission原始碼解析原始碼
- Express原始碼解析Express原始碼
- redux原始碼解析Redux原始碼
- CopyOnWriteArrayList原始碼解析原始碼
- LeakCanary原始碼解析原始碼
- ArrayBlockQueue原始碼解析BloC原始碼
- ReentrantLock原始碼解析ReentrantLock原始碼
- OKio原始碼解析原始碼
- ReentrantReadWriteLock原始碼解析原始碼
- CyclicBarrier原始碼解析原始碼
- Semaphore原始碼解析原始碼
- Exchanger原始碼解析原始碼
- SDWebImage原始碼解析Web原始碼
- AbstractQueuedSynchronizer原始碼解析原始碼
- LinkedList原始碼解析原始碼
- HandlerThread原始碼解析thread原始碼
- ButterKnife原始碼解析原始碼
- SpringMVC原始碼解析SpringMVC原始碼
- RecyclerView原始碼解析View原始碼
- MyBatis原始碼解析MyBatis原始碼
- CountDownLatch原始碼解析CountDownLatch原始碼
- Promise 原始碼解析Promise原始碼
- Mansonry原始碼解析原始碼
- Observer原始碼解析Server原始碼
- SparseArray 原始碼解析原始碼
- Ribbon原始碼解析原始碼
- AsyncTask原始碼解析原始碼
- linker原始碼解析原始碼
- vuex原始碼解析Vue原始碼
- LeakCanary 原始碼解析原始碼
- Vue原始碼解析Vue原始碼
- Hive原始碼解析Hive原始碼