天天看點

帶你一步步剖析Retrofit-源碼解析:一款基于-OkHttp-實作的網絡請求架構

int question = value.indexOf(’?’);

if (question != -1 && question < value.length() - 1) {

// Ensure the query string does not have any named parameters.

String queryParams = value.substring(question + 1);

Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams);

if (queryParamMatcher.find()) {

throw methodError(method, "URL query string “%s” must not have replace block. "+ “For dynamic query parameters use @Query.”, queryParams);

}

}

this.relativeUrl = value;

this.relativeUrlParamNames = parsePathParameters(value);

}

這裡實際上就是對不同 HTTP 請求方式和 Path 進行了指派,同時通過正規表達式保證了這個接口的 Path 中沒有包含參數。

對 Headers 的處理

private Headers parseHeaders(String[] headers) {

Headers.Builder builder = new Headers.Builder();

for (String header : headers) {

int colon = header.indexOf(’:’);

if (colon == -1 || colon == 0 || colon == header.length() - 1) {

throw methodError(method,

“@Headers value must be in the form “Name: Value”. Found: “%s””, header);

}

String headerName = header.substring(0, colon);

String headerValue = header.substring(colon + 1).trim();

if (“Content-Type”.equalsIgnoreCase(headerName)) {

try {

contentType = MediaType.get(headerValue);

} catch (IllegalArgumentException e) {

throw methodError(method, e, “Malformed content type: %s”, headerValue);

}

} else {

builder.add(headerName, headerValue);

}

}

return builder.build();

}

而對于 Headers 則是将傳遞進來的

Headers

清單解析為了對應的

Headers

對象。

對方法參數的處理
最後我們看看對方法參數的處理:

private @Nullable ParameterHandler<?> parseParameter(

int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {

ParameterHandler<?> result = null;

if (annotations != null) {

for (Annotation annotation : annotations) {

// 對每個注解通過 parseParameterAnnotation 進行解析

ParameterHandler<?> annotationAction =

parseParameterAnnotation(p, parameterType, annotations, annotation);

if (annotationAction == null) {

continue;

}

if (result != null) {

throw parameterError(method, p,

“Multiple Retrofit annotations found, only one allowed.”);

}

result = annotationAction;

}

}

if (result == null) {

// 在協程的情況下對進行特殊處理

if (allowContinuation) {

try {

if (Utils.getRawType(parameterType) == Continuation.class) {

isKotlinSuspendFunction = true;

return null;

}

} catch (NoClassDefFoundError ignored) {

}

}

throw parameterError(method, p, “No Retrofit annotation found.”);

}

return result;

}

parseParamterAnnotation

方法的代碼太長了,這裡就不再貼了,它對方法的每個注解都進行了獨有的處理,并傳回了對應的

ParamterHandler

可以發現,

RequestFactory.parseAnnotations

的主要作用就是完成對方法注解資訊的解析,進而用于産生對應的

Request

ServiceMethod 的建立

之後我們接着看看

HttpServiceMethod.parseAnnotations

static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(

Retrofit retrofit, Method method, RequestFactory requestFactory) {

boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;

boolean continuationWantsResponse = false;

boolean continuationBodyNullable = false;

Annotation[] annotations = method.getAnnotations();

Type adapterType;

if (isKotlinSuspendFunction) {

// 如果方法是 kotlin 中的 suspend 方法

Type[] parameterTypes = method.getGenericParameterTypes();

// 擷取 Continuation 的範型參數,它就是 suspend 方法的傳回值類型

Type responseType = Utils.getParameterLowerBound(0,

(ParameterizedType) parameterTypes[parameterTypes.length - 1]);

// 如果 Continuation 的範型參數是 Response,則說明它需要的是 Response,那麼将 continuationWantsResponse 置為 true;

if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {

// Unwrap the actual body type from Response.

responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);

continuationWantsResponse = true;

} else {

// TODO figure out if type is nullable or not

// Metadata metadata = method.getDeclaringClass().getAnnotation(Metadata.class)

// Find the entry for method

// Determine if return type is nullable or not

}

adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);

annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);

} else {

// 否則擷取方法傳回值的範型參數,即為請求需要的傳回值的類型

adapterType = method.getGenericReturnType();

}

// 通過 createCallAdapter 方法建立 CallAdapter 對象

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)”);

    }

    // TODO support Unit for Kotlin?

    if (requestFactory.httpMethod.equals(“HEAD”) && !Void.class.equals(responseType)) {

    throw methodError(method, “HEAD method must use Void as response type.”);

    }

    // 通過 createResponseConverter 方法建立 Converter對象

    Converter<ResponseBody, ResponseT> responseConverter =

    createResponseConverter(retrofit, method, responseType);

    okhttp3.Call.Factory callFactory = retrofit.callFactory;

    if (!isKotlinSuspendFunction) {

    // 不是suspend方法的話則直接建立并傳回一個 CallAdapted 對象

    return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);

    } else if (continuationWantsResponse) {

    //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.

    return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForResponse<>(requestFactory,

    callFactory, responseConverter, (CallAdapter<ResponseT, Call>) callAdapter);

    } else {

    //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.

    return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForBody<>(requestFactory,

    callFactory, responseConverter, (CallAdapter<ResponseT, Call>) callAdapter,

    continuationBodyNullable);

    }

    }

這裡的代碼非常非常長,大緻可歸納為下面的步驟:

1. 如果這個方法是 Kotlin 中的 suspend 方法,由于由協程實作,是以需要擷取

Continuation

的範型參數,這個參數就是請求傳回值的真正類型。

2. 如果

suspend

方法傳回值是

Response

,則說明它需要的是 Response 而不是具體的類型,那麼将

continuationWantsResponse

置為 true;

3. 如果不是

suspend

方法,則傳回值的範型參數的類型就是請求傳回值的真正類型(

Call<ReturnType>

ReturnType

才是真正經過轉換後需要的類型)。

4. 通過

createCallAdapter

方法建立

CallAdapter

對象,它是用于将

Call<ResponseT>

對象适配為需要的類型

ReturnT

對象的。

5. 拿到

CallAdapter

後,擷取到了

Response

的類型,并進行了校驗。

6. 通過

createResponseConverter

方法擷取

Converter

對象,它可以完成從

ResponseBody

Response

類型

ResponseT

的轉換。

7. 如果并非 Kotlin 的 suspend 方法,則直接傳入

CallAdapter

及 Converter,建立

CallAdapted

對象。

8. 否則根據 suspend 方法需要的是

Response

還是具體的類型,分别傳回

SuspendForResponse

SuspendForBody

對象。

可以發現,新版的 Retrofit 對 Kotlin 的協程進行了支援。

HttpServiceMethod.parseAnnotations

的主要作用就是建立

CallAdapter

以及 Converter 對象,并建構對應

HttpServiceMethod

CallAdapter

CallAdapter

是用于将

Call<R>

對象适配為需要的類型 T 對象的。它的聲明如下:

public interface CallAdapter<R, T> {

// 傳回 Response 的類型

Type responseType();

// 将 Call 轉換為 T 類型

T adapt(Call call);

}

我們先看看

createCallAdapter

方法是如何對它建立的:

private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(

Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {

try {

//noinspection unchecked

return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);

} catch (RuntimeException e) { // Wide exception range because factories are user code.

throw methodError(method, e, “Unable to create call adapter for %s”, returnType);

}

}

它調用了

retrofit.callAdapter

方法:

public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {

return nextCallAdapter(null, returnType, annotations);

}

之後調用到

retrofit.nextCallAdapter

方法:

public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,

Annotation[] annotations) {

Objects.requireNonNull(returnType, “returnType == null”);

Objects.requireNonNull(annotations, “annotations == null”);

int start = callAdapterFactories.indexOf(skipPast) + 1;

for (int i = start, count = callAdapterFactories.size(); i < count; i++) {

// 周遊 callAdapterFactories,嘗試建立 CallAdapter

CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);

if (adapter != null) {

return adapter;

}

}

// …不存在對應的 CallAdapterFactory,抛出異常

}

這裡實際上是周遊了建立 Retrofit 對象時傳遞的

CallAdapter.Factory

清單嘗試去建立

CallAdapter

。如果這些

CallAdapter.Factory

都無法處理這個對應的

returnType

以及

annotations

的話,則會抛出異常。(前面 Factory 的優先級更高)

Retrofit 中有一個預設的

CallAdapter

工廠

DefaultCallAdapterFactory

,它的優先級比所有自定義工廠要低,它在建立時會傳入一個

Executor

,我們可以看到它的 get 方法:

@Override public @Nullable CallAdapter<?, ?> get(

Type returnType, Annotation[] annotations, Retrofit retrofit) {

if (getRawType(returnType) != Call.class) {

return null;

}

if (!(returnType instanceof ParameterizedType)) {

throw new IllegalArgumentException(

“Call return type must be parameterized as Call or Call<? extends Foo>”);

}

final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);

final Executor executor = Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)

? null: callbackExecutor;

return new CallAdapter<Object, Call<?>>() {

@Override public Type responseType() {

return responseType;

}

@Override public Call adapt(Call call) {

return executor == null

? call: new ExecutorCallbackCall<>(executor, call);

}

};

}

可以看到,在沒有

Executor

時,它不對 Call 進行修改,在有指定 Executor 時,則會将其包裝為

ExecutorCallbackCall

。一般來說這個

帶你一步步剖析Retrofit-源碼解析:一款基于-OkHttp-實作的網絡請求架構

Executor 就是建立 Retrofit 時指定的

callbackExecutor

這個

callbackExecutor

實際上是用來指定調用

Callback

的線程的,進而使得

Callback

并不一定是在主線程被回調:

static final class ExecutorCallbackCall implements Call {

final Executor callbackExecutor;

final Call delegate;

ExecutorCallbackCall(Executor callbackExecutor, Call delegate) {

this.callbackExecutor = callbackExecutor;

this.delegate = delegate;

}

@Override public void enqueue(final Callback callback) {

Objects.requireNonNull(callback, “callback == null”);

// 對 Callback 進行了包裝,通過 callbackExecutor 進行回調

delegate.enqueue(new Callback() {

@Override public void onResponse(Call call, final Response response) {

callbackExecutor.execute(() -> {

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 call, final Throwable t) {

callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));

}

});

}

// …

}

可以看到,這裡實際上隻是對 Callback 進行了包裝,通過傳遞的 Executor 進行回調,進而對

callbackExecutor

進行支援。

Converter

接着我們看看

Converter

類,它是一個接口,用于将類型 F 的資料轉換為類型 T:

public interface Converter<F, T> {

@Nullable T convert(F value) throws IOException;

// …

}

接着我們看看

createResponseConverter

是如何對它進行建立的:

private static Converter<ResponseBody, ResponseT> createResponseConverter(

Retrofit retrofit, Method method, Type responseType) {

Annotation[] annotations = method.getAnnotations();

try {

return retrofit.responseBodyConverter(responseType, annotations);

} catch (RuntimeException e) { // Wide exception range because factories are user code.

throw methodError(method, e, “Unable to create converter for %s”, responseType);

}

}

轉調到了

retrofit.responseBodyConverter

public Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {

return nextResponseBodyConverter(null, type, annotations);

}

轉調到了

nextResponseBodyConverter

public Converter<ResponseBody, T> nextResponseBodyConverter(

@Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {

Objects.requireNonNull(type, “type == null”);

Objects.requireNonNull(annotations, “annotations == null”);

int start = converterFactories.indexOf(skipPast) + 1;

for (int i = start, count = converterFactories.size(); i < count; i++) {

Converter<ResponseBody, ?> converter =

converterFactories.get(i).responseBodyConverter(type, annotations, this);

if (converter != null) {

//noinspection unchecked

return (Converter<ResponseBody, T>) converter;

}

}

// 沒有找到對應的 ConverterFactory 進行處理,抛出異常

}

可以看到,這裡與

CallAdapter

工廠類似,周遊建立 Retrofit 時傳入的

Converter.Factory

清單,嘗試進行建立,如果沒有工廠能對其進行處理,抛出異常。(前面 Factory 的優先級更高)

Retrofit

中内置了兩個

Converter.Factory

,分别是

BuiltInConverters

以及

OptionalConverterFactory

其中

BuiltInConverters

的優先級比所有自定義工廠要高,以避免其他工廠覆寫它的方法,而

OptionalConverterFactory

的優先級比所有自定義工廠的優先級更低。

BuiltInConverters

中實作了多個轉換器如将

ResponseBody

轉換為 Void 或 Unit,将 Object 轉換為 String 等。

OptionalConverterFactory

是通過 platform 擷取到的

defaultConverterFactories

,它是為了支援 Java 8 的 Optional 而實作的,Optional 是 Java 8 引入的用來解決空指針異常的類。

ServiceMethod

接着我們看看之前建立的

ServiceMethod

類,它是一個抽象類,需要子類對 invoke 方法進行實作。

abstract class ServiceMethod {

abstract @Nullable T invoke(Object[] args);

}

它的子類就是前面提到的

HttpServiceMethod

HttpServiceMethod

abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod {

@Override final @Nullable ReturnT invoke(Object[] args) {

Call call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);

return adapt(call, args);

}

protected abstract @Nullable ReturnT adapt(Call call, Object[] args);

}

HttpServiceMethod

的 invoke 方法非常簡單,它構造了一個

OkHttpCall

,然後通過 adapt 這個虛函數來實作對 Call 的轉換。它的子類隻需要實作 adapt 進而對 Call 進行轉換即可。

它共有三個子類,首先就是并非使用協程的情況下的

CallAdapted

類,另外兩個子類則是在使用協程的情況下為了配合協程的

SuspendForResponse

以及

SuspendForBody

CallAdapted

CallAdapted

類繼承自

HttpServiceMethod

類,并通過傳遞進來的

CallAdapter

對 Call 進行了轉換。

static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {

private final CallAdapter<ResponseT, ReturnT> callAdapter;

CallAdapted(RequestFactory requestFactory, okhttp3.Call.Factory callFactory,

Converter<ResponseBody, ResponseT> responseConverter,

CallAdapter<ResponseT, ReturnT> callAdapter) {

super(requestFactory, callFactory, responseConverter);

this.callAdapter = callAdapter;

}

@Override protected ReturnT adapt(Call call, Object[] args) {

return callAdapter.adapt(call);

}

}

SuspendForResponse

SuspendForResponse

類首先根據傳遞進來的 Call 構造了一個參數為

Response<ResponseT>

Continuation

對象然後通過 Kotlin 實作的

awaitResponse

方法将 call 的

enqueue

異步回調過程封裝為了一個 suspend 的函數。

static final class SuspendForResponse extends HttpServiceMethod<ResponseT, Object> {

private final CallAdapter<ResponseT, Call> callAdapter;

SuspendForResponse(RequestFactory requestFactory, okhttp3.Call.Factory callFactory,

Converter<ResponseBody, ResponseT> responseConverter,

CallAdapter<ResponseT, Call> callAdapter) {

super(requestFactory, callFactory, responseConverter);

this.callAdapter = callAdapter;

}

@Override protected Object adapt(Call call, Object[] args) {

call = callAdapter.adapt(call);

//noinspection unchecked Checked by reflection inside RequestFactory.

Continuation<Response> continuation =

(Continuation<Response>) args[args.length - 1];

// See SuspendForBody for explanation about this try/catch.

try {

return KotlinExtensions.awaitResponse(call, continuation);

} catch (Exception e) {

return KotlinExtensions.suspendAndThrow(e, continuation);

}

}

}

awaitResponse

方法如下:

suspend fun Call.awaitResponse(): Response {

return suspendCancellableCoroutine { continuation ->

continuation.invokeOnCancellation {

cancel()

}

enqueue(object : Callback {

override fun onResponse(call: Call, response: Response) {

continuation.resume(response)

}

override fun onFailure(call: Call, t: Throwable) {

continuation.resumeWithException(t)

}

})

}

}

可以看到,分别通過在

onResponse

onFailure

中調用

continuation.resume

continuation.resumeWithException

進而對協程進行支援。

SuspendForBody

SuspendForBody

則是根據傳遞進來的 Call 構造了一個

Continuation<ResponseT>

對象然後通過 Kotlin 實作的 await 或

awaitNullable

方法将 call 的

enqueue

異步回調過程封裝為了一個 suspend 的函數。

static final class SuspendForBody extends HttpServiceMethod<ResponseT, Object> {

private final CallAdapter<ResponseT, Call> callAdapter;

private final boolean isNullable;

SuspendForBody(RequestFactory requestFactory, okhttp3.Call.Factory callFactory,

Converter<ResponseBody, ResponseT> responseConverter,

CallAdapter<ResponseT, Call> callAdapter, boolean isNullable) {

super(requestFactory, callFactory, responseConverter);

this.callAdapter = callAdapter;

this.isNullable = isNullable;

}

@Override protected Object adapt(Call call, Object[] args) {

call = callAdapter.adapt(call);

//noinspection unchecked Checked by reflection inside RequestFactory.

Continuation continuation = (Continuation) args[args.length - 1];

// Calls to OkHttp Call.enqueue() like those inside await and awaitNullable can sometimes

// invoke the supplied callback with an exception before the invoking stack frame can return.

// Coroutines will intercept the subsequent invocation of the Continuation and throw the

// exception synchronously. A Java Proxy cannot throw checked exceptions without them being

// in an UndeclaredThrowableException, it is intercepted and supplied to a helper which will

// force suspension to occur so that it can be instead delivered to the continuation to

// bypass this restriction.

try {

return isNullable

? KotlinExtensions.awaitNullable(call, continuation)

: KotlinExtensions.await(call, continuation);

} catch (Exception e) {

return KotlinExtensions.suspendAndThrow(e, continuation);

}

}

}

Call

Call 實際上是一個接口,它提供了

execute

enqueue

cancel

等接口用于實作請求,當我們需要請求一個接口的時候,隻需要調用其

enqueue

execute

方法即可。

public interface Call extends Cloneable {

Response execute() throws IOException;

void enqueue(Callback callback);

boolean isExecuted();

void cancel();

boolean isCanceled();

Call clone();

Request request();

}

從前面的過程中我們可以了解到,如果我們沒有傳入

CalAdapter

的話,預設情況下傳回的 Call 實際上是

OkHttpCall

對象,讓我們通過它來看看 Retrofit 如何基于

OkHttp

實作的網絡請求:

enqueue

首先讓我們看看

enqueue

的代碼:

@Override public void enqueue(final Callback callback) {

Objects.requireNonNull(callback, “callback == null”);

okhttp3.Call call;

Throwable failure;

// 加鎖,對狀态進行設定并通過 createRawCall 方法建立 okhttp3.Call

synchronized (this) {

if (executed) throw new IllegalStateException(“Already executed.”);

executed = true;

call = rawCall;

failure = creationFailure;

if (call == null && failure == null) {

try {

call = rawCall = createRawCall();

} catch (Throwable t) {

throwIfFatal(t);

failure = creationFailure = t;

}

}

}

if (failure != null) {

callback.onFailure(this, failure);

return;

}

// 如果外界取消該任務,則調用 okhttp3.Call.cancel

if (canceled) {

call.cancel();

}

// 通過 okhttp3.Call.enqueue 将消息入隊

call.enqueue(new okhttp3.Callback() {

@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {

Response response;

try {

// 獲得結果後通過 parseResponse 進行解析

response = parseResponse(rawResponse);

} catch (Throwable e) {

throwIfFatal(e);

callFailure(e);

return;

}

try {

// 解析完成後通過 onResponse 進行回調

callback.onResponse(OkHttpCall.this, response);

} catch (Throwable t) {

throwIfFatal(t);

t.printStackTrace(); // TODO this is not great

}

}

@Override public void onFailure(okhttp3.Call call, IOException e) {

// 請求失敗調用 callFailure 回調失敗請求

callFailure(e);

}

private void callFailure(Throwable e) {

try {

callback.onFailure(OkHttpCall.this, e);

} catch (Throwable t) {

throwIfFatal(t);

t.printStackTrace(); // TODO this is not great

}

}

});

}

enqueue

的代碼看似多,實際上比較簡單,主要分為以下幾步:

1. 加鎖,對執行狀态進行設定,若不存在 rawCall 則調用 createRawCall 方法建立 okhttp3.Call 對象。

2. 如果外界取消該任務,則調用 okhttp3.Call.cancel

3. 通過 okhttp3.Call.enqueue 将消息入隊

4. 若獲得 Response,則通過 parseResponse 方法對 Response 進行解析,解析完成後通過 onResponse 回調解析結果。

5. 若請求失敗,通過 callFailure 方法調用 onFailure 回調請求失敗。

可以發現一個小細節,Retrofit 對已經建立的

okhttp3.Call

進行了複用,避免了重複建立進而浪費效率。

execute

接着讓我們看看

execute

是如何實作的:

@Override public Response 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 if (creationFailure instanceof RuntimeException) {

throw (RuntimeException) creationFailure;

} else {

throw (Error) creationFailure;

}

}

call = rawCall;

if (call == null) {

try {

,避免了重複建立進而浪費效率。**

execute

接着讓我們看看

execute

是如何實作的:

@Override public Response 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 if (creationFailure instanceof RuntimeException) {

throw (RuntimeException) creationFailure;

} else {

throw (Error) creationFailure;

}

}

call = rawCall;

if (call == null) {

try {