前言
上篇文章我們分析了OkHttp的原理幸逆,不難看出它更多的還是和TCP/IP打交道棠耕,做了請求和響應(yīng)的處理吹零,今天我們來介紹另外一位主人公,那就是我們的Retrofit滨嘱,它更多的是對OkHttp做了一層封裝峰鄙,方便了我們調(diào)用接口,并且對數(shù)據(jù)進行了轉(zhuǎn)化太雨,對業(yè)務(wù)側(cè)更加友好吟榴。
首先我們來看看它的初始化,慢慢剖析它的源碼吧囊扳。
Retrofit retrofit = new Retrofit.Builder().baseUrl(BaseUrl.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(httpClient)
.build();
老相識又出現(xiàn)了Builder吩翻,我們接著看
Retrofit.Builder()
Builder(Platform platform) {
this.platform = platform;
}
public Builder() {
this(Platform.get());
}
代碼很清楚,這里進行了平臺的獲取并且賦值锥咸。
Builder.baseUrl
public Builder baseUrl(String baseUrl) {
Objects.requireNonNull(baseUrl, "baseUrl == null");
return baseUrl(HttpUrl.get(baseUrl));
}
public Builder baseUrl(HttpUrl baseUrl) {
Objects.requireNonNull(baseUrl, "baseUrl == null");
List<String> pathSegments = baseUrl.pathSegments();
if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
}
this.baseUrl = baseUrl;
return this;
}
這里也是比較簡單就是對baseUrl進行賦值狭瞎,返回當(dāng)前的Builder對象。后面的幾個基本都一樣搏予,感興趣的可以自己追一下熊锭。
Builder.build
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
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> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories = new ArrayList<>(
1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
// Add the built-in converter factory first. This prevents overriding its behavior but also
// ensures correct behavior when using converters that consume all types.
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(platform.defaultConverterFactories());
//返回一個 創(chuàng)建的Retrofit對象
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
我們接著看看Retrofit的創(chuàng)建,如下:
Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
List<Converter.Factory> converterFactories, List<CallAdapter.Factory> callAdapterFactories,
@Nullable Executor callbackExecutor, boolean validateEagerly) {
this.callFactory = callFactory;
this.baseUrl = baseUrl;
this.converterFactories = converterFactories; // Copy+unmodifiable at call site.
this.callAdapterFactories = callAdapterFactories; // Copy+unmodifiable at call site.
this.callbackExecutor = callbackExecutor;
this.validateEagerly = validateEagerly;
}
其實也是簡單的一些屬性的賦值雪侥。到這里我們簡單的Retrofit創(chuàng)建就完成了碗殷。下面分析大頭,接口的創(chuàng)建請求以及調(diào)用回調(diào)速缨⌒科蓿’
public interface OKHttpService {
/**
* 登錄接口demo
*/
@FormUrlEncoded
@POST("user/login")
Call<ResponseBody> login(@Field("username") String num, @Field("password") String password);
我這里簡單創(chuàng)建了個登錄接口。
OKHttpService httpService = retrofit.create(OKHttpService.class);
httpService.login("zc", "123123").enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
Log.i("ZC", "成功: " + Thread.currentThread());
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.i("ZC", "失敗: " + Thread.currentThread());
}
});
接著我們通過create去創(chuàng)建并且發(fā)送請求旬牲,我們一步步的看下去:
create
public <T> T create(final Class<T> 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 {
// 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);
}
//loadServiceMethod創(chuàng)建的代理方法對象,其內(nèi)部包含了login方法的注解參數(shù),返回值,以及各個工廠以及各請求器轉(zhuǎn)換器等等的適配操作
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
這里的invoke我們在下面分析仿粹。
動態(tài)代理模式:在程序運行期間,通過反射機制,動態(tài)創(chuàng)建OkhttpService.class的代理對象,并且對該對象中的方法增加一些其他操作
newProxyInstance
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
//若interface沒有重寫clone(),默認的是進行一次淺拷貝,即實例對象相同,引用不同
final Class<?>[] intfs = interfaces.clone();
// Android-removed: SecurityManager calls
/*
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
*/
/*
* Look up or generate the designated proxy class.
*生成或獲取(緩存中)代理類的Class對象
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
// Android-removed: SecurityManager / permission checks.
/*
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
*/
//通過Class對象獲取構(gòu)造方法
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
// BEGIN Android-removed: Excluded AccessController.doPrivileged call.
/*
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
*/
cons.setAccessible(true);
// END Android-removed: Excluded AccessController.doPrivileged call.
}
//通過構(gòu)造方法創(chuàng)建實例對象
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
getProxyClass0獲取的Class對象其實是個單例模式,在第一次時會創(chuàng)建實例并將其存入WeakCache做緩存,之后的獲取會直接從緩存中獲取Class對象,至于其他一些操作,多為反射機制實例化對象常用的調(diào)用引谜。
還有一點我們需要記住的是牍陌,InvocationHandler內(nèi)部的invoke被調(diào)用是我們通過newProxyInstance()返回的代理類對象(OKHttpService的代理實現(xiàn)類)調(diào)用login()時,觸發(fā)invoke()员咽。
至此我們就簡單的分析完了Proxy.newProxyInstance()中的源碼,我們繼續(xù)回到create()源碼中,return代理對象,至此OKHttpService接口的代理對象就被創(chuàng)建了,接下來就要使用代理對象OKHttpService調(diào)用login()方法了毒涧。
調(diào)用login()時我們會調(diào)用InvocationHandler#invoke()。
ServiceMethod對象實例化
一個ServiceMethod對象對應(yīng)了一個網(wǎng)絡(luò)接口中的方法,該對象中保存有方法的處理網(wǎng)絡(luò)請求所要用到的各種參數(shù)及方法的屬性注解等,閱讀源碼時要搞清楚serviceMethod的性質(zhì),這里調(diào)用了loadServiceMethod()我們進入方法內(nèi)部看看贝室。
loadServiceMethod
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);
}
}
return result;
}
同樣,首先會從緩存中獲取對象,為null才會創(chuàng)建實例對象,也是一個單例對象,在Builer()中會將解析method一些信息(參數(shù),注解,參數(shù)注解)和retrofit對象中的屬性,并保存到serviceMethod對象中契讲。
延伸知識點(繼續(xù)深追源碼):ServiceMethod不僅存儲了method(也就是login()方法)的參數(shù),屬性等,還存儲有各種適配器,轉(zhuǎn)換器,和http協(xié)議要求的一些相關(guān)check,需要結(jié)合http相關(guān)的知識來理解。這里直接給結(jié)論滑频,就不繼續(xù)追了捡偏。
HttpServiceMethod#invoke
@Override final @Nullable ReturnT invoke(Object[] args) {
//創(chuàng)建一個網(wǎng)絡(luò)請求器,所以說Retrofit底層默認是使用okhttp實現(xiàn)的
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
//將okhttpcall對象與網(wǎng)絡(luò)請求適配器進行綁定
return adapt(call, args);
}
不難看出,它創(chuàng)建了個OkHttpCall對象峡迷,retrofit2#OkHttpCall重寫了execute()和enqueue方法等,在隨后的網(wǎng)絡(luò)請求適配器調(diào)用中,就會執(zhí)行此方法來通過OkHttp請求訪問網(wǎng)絡(luò)
adapt(call, args)
將創(chuàng)建的okHttpCall對象與serviceMethod中的網(wǎng)絡(luò)請求適配器適配,內(nèi)部return callAdapter.adapt(call);而此callAdapter還記得在哪獲取的?
它是在serviceMethod.loadServiceMethod(method)內(nèi)的createCallAdapter()中選擇的,所以這里的引用是之前選擇的網(wǎng)絡(luò)請求適配器類對象的adapt(),我們就先看一下它默認的網(wǎng)絡(luò)請求適配器也就是DefaultCallAdapterFactory银伟。
DefaultCallAdapterFactory #get#CallAdapter#adapt
@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<Foo> 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<Object> adapt(Call<Object> call) {
return executor == null
? call
: new ExecutorCallbackCall<>(executor, call);
}
};
}
當(dāng)執(zhí)行了serviceMethod.adapt(okHttpCall)時,其實(默認)調(diào)用了此處的adapt()方法,返回一個call對象你虹。
小小整理一下:
當(dāng)客戶端調(diào)用login()方法時,是使用的Proxy.newProxyInstance()返回的代理實例對象httpService去調(diào)用的,并且會回調(diào)InvocationHandler中的invoke()方法,執(zhí)行代理操作,最后通過adapt()返回一個call對象。
ExecutorCallbackCall
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;
}
public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
//delegate是在實例化ExecutorCallbackCall時傳遞的第二個參數(shù),對象為OkHttpCall彤避,也就是說這里enqueue()又委托給了OkHttpCall來執(zhí)行
this.delegate.enqueue(new Callback<T>() {
public void onResponse(Call<T> call, Response<T> response) {
//在Android環(huán)境中運行callbackExecutor默認為MainThreadExecutor,當(dāng)網(wǎng)絡(luò)請求成功,執(zhí)行切回到主線程中,回調(diào)客戶端的callback對象的onResponse()方法
ExecutorCallbackCall.this.callbackExecutor.execute(() -> {
if (ExecutorCallbackCall.this.delegate.isCanceled()) {
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
});
}
public void onFailure(Call<T> call, Throwable t) {
//失敗同樣也會切換到主線程去回調(diào)callback的onFailure()
ExecutorCallbackCall.this.callbackExecutor.execute(() -> {
callback.onFailure(ExecutorCallbackCall.this, t);
});
}
});
}
public boolean isExecuted() {
return this.delegate.isExecuted();
}
public Response<T> execute() throws IOException {
return this.delegate.execute();
}
public void cancel() {
this.delegate.cancel();
}
public boolean isCanceled() {
return this.delegate.isCanceled();
}
public Call<T> clone() {
return new DefaultCallAdapterFactory.ExecutorCallbackCall(this.callbackExecutor, this.delegate.clone());
}
public Request request() {
return this.delegate.request();
}
}
調(diào)用login的時候返回了一個Call傅物,然后調(diào)用enqueue,我們就能看的出就是調(diào)用的這里(默認)琉预,其實內(nèi)部調(diào)用的是delegate.enqueue()董饰,也就是我們上文提到過得OkHttpCall的enqueue,調(diào)用okhttp3完成請求圆米,拿到回調(diào)并且處理Response回調(diào)卒暂。
ExecutorCallbackCall.this.callbackExecutor
這里其實還有個這個東西需要說明下,callbackExecutor默認是個啥娄帖,這里我們就可以追到
Android
static final class Android extends Platform {
Android() {
super(Build.VERSION.SDK_INT >= 24);
}
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
真正調(diào)用接口的實現(xiàn)
OkHttpCall#enqueue
@Override public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(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 {
//創(chuàng)建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();
}
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
throwIfFatal(e);
callFailure(e);
return;
}
try {
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(e);
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
throwIfFatal(t);
t.printStackTrace(); // TODO this is not great
}
}
});
}
接著追一下createRawCall()
createRawCall
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
RequestFactory#create()
okhttp3.Request create(Object[] args) throws IOException {
@SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
int argumentCount = args.length;
if (argumentCount != handlers.length) {
throw new IllegalArgumentException("Argument count (" + argumentCount
+ ") doesn't match expected count (" + handlers.length + ")");
}
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl,
headers, contentType, hasBody, isFormEncoded, isMultipart);
省略...
return requestBuilder.get()
.tag(Invocation.class, new Invocation(method, argumentList))
.build();
}
這里可以看到創(chuàng)建了個RequestBuilder也祠,對一些屬性進行了賦值,接著看get块茁,
RequestBuilder#get()
Request.Builder get() {
HttpUrl url;
HttpUrl.Builder urlBuilder = this.urlBuilder;
if (urlBuilder != null) {
url = urlBuilder.build();
} else {
// No query parameters triggered builder creation, just combine the relative URL and base URL.
//noinspection ConstantConditions Non-null if urlBuilder is null.
url = baseUrl.resolve(relativeUrl);
if (url == null) {
throw new IllegalArgumentException(
"Malformed URL. Base: " + baseUrl + ", Relative: " + relativeUrl);
}
}
RequestBody body = this.body;
if (body == null) {
// Try to pull from one of the builders.
if (formBuilder != null) {
body = formBuilder.build();
} else if (multipartBuilder != null) {
body = multipartBuilder.build();
} else if (hasBody) {
// Body is absent, make an empty body.
body = RequestBody.create(null, new byte[0]);
}
}
MediaType contentType = this.contentType;
if (contentType != null) {
if (body != null) {
body = new ContentTypeOverridingRequestBody(body, contentType);
} else {
headersBuilder.add("Content-Type", contentType.toString());
}
}
return requestBuilder
.url(url)
.headers(headersBuilder.build())
.method(method, body);
}
到這里我們就能看到Okhttp3的Request以及它的內(nèi)部類Builder了齿坷,到這里就終于揭開神秘面紗,打通Retrofit和OkHttp了数焊。后面就是構(gòu)建OkHttp的request以及Call了,然后通過OkHttp的Call去請求崎场,回調(diào)處理轉(zhuǎn)換類型佩耳。這里就不再細分下去了。對于OkHttp的原理感興趣的可以看我之前的博客谭跨。
總結(jié)一下上面的流程:
這里首先根據(jù)serviceMethod中關(guān)于login()方法的屬性以及解析的注解信息創(chuàng)建request請求對象,最后通過return callFactory.newCall(requestBuilder.build());
callFactory默認是OkHttpClient,我們就不在深入展示了,最終在其內(nèi)部返回的是一個RealCall,有興趣的可以進去了解一下OkHttpClient源碼,到了這里,Retrofit的網(wǎng)絡(luò)請求底層便顯露在我們眼前,從這里我們就可以看到,Retrofit使用的網(wǎng)絡(luò)底層為OkHttp
接下來退回到enqueue()方法體內(nèi),之后調(diào)用call(RealCall)對象的enqueue()來處理網(wǎng)絡(luò)請求了,至于之后的事情,就是OkHttp底層要做的了干厚。
最后我們使用RealCall調(diào)用enqueue()傳入的Callback對象,Callback的onResponse通過parseResponse()完成數(shù)據(jù)轉(zhuǎn)換螃宙。成功回調(diào)onResponse,失敗回調(diào)onFailure(),最后客戶端就可以看到網(wǎng)絡(luò)的訪問狀況了蛮瞄。