前言
上篇文章我們分析了OkHttp的原理,不難看出它更多的還是和TCP/IP打交道,做了請(qǐng)求和響應(yīng)的處理,今天我們來介紹另外一位主人公,那就是我們的Retrofit,它更多的是對(duì)OkHttp做了一層封裝,方便了我們調(diào)用接口,并且對(duì)數(shù)據(jù)進(jìn)行了轉(zhuǎn)化,對(duì)業(yè)務(wù)側(cè)更加友好。
首先我們來看看它的初始化,慢慢剖析它的源碼吧。
Retrofit retrofit = new Retrofit.Builder().baseUrl(BaseUrl.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(httpClient)
.build();
老相識(shí)又出現(xiàn)了Builder,我們接著看
Retrofit.Builder()
Builder(Platform platform) {
this.platform = platform;
}
public Builder() {
this(Platform.get());
}
代碼很清楚,這里進(jìn)行了平臺(tái)的獲取并且賦值。
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;
}
這里也是比較簡單就是對(duì)baseUrl進(jìn)行賦值,返回當(dāng)前的Builder對(duì)象。后面的幾個(gè)基本都一樣,感興趣的可以自己追一下。
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());
//返回一個(gè) 創(chuàng)建的Retrofit對(duì)象
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;
}
其實(shí)也是簡單的一些屬性的賦值。到這里我們簡單的Retrofit創(chuàng)建就完成了。下面分析大頭,接口的創(chuàng)建請(qǐ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)建了個(gè)登錄接口。
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ā)送請(qǐng)求,我們一步步的看下去:
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)建的代理方法對(duì)象,其內(nèi)部包含了login方法的注解參數(shù),返回值,以及各個(gè)工廠以及各請(qǐng)求器轉(zhuǎn)換器等等的適配操作
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
這里的invoke我們?cè)谙旅娣治觥?/p>
動(dòng)態(tài)代理模式:在程序運(yùn)行期間,通過反射機(jī)制,動(dòng)態(tài)創(chuàng)建OkhttpService.class的代理對(duì)象,并且對(duì)該對(duì)象中的方法增加一些其他操作
newProxyInstance
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
//若interface沒有重寫clone(),默認(rèn)的是進(jìn)行一次淺拷貝,即實(shí)例對(duì)象相同,引用不同
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對(duì)象
*/
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對(duì)象獲取構(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)建實(shí)例對(duì)象
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對(duì)象其實(shí)是個(gè)單例模式,在第一次時(shí)會(huì)創(chuàng)建實(shí)例并將其存入WeakCache做緩存,之后的獲取會(huì)直接從緩存中獲取Class對(duì)象,至于其他一些操作,多為反射機(jī)制實(shí)例化對(duì)象常用的調(diào)用。
還有一點(diǎn)我們需要記住的是,InvocationHandler內(nèi)部的invoke被調(diào)用是我們通過newProxyInstance()返回的代理類對(duì)象(OKHttpService的代理實(shí)現(xiàn)類)調(diào)用login()時(shí),觸發(fā)invoke()。
至此我們就簡單的分析完了Proxy.newProxyInstance()中的源碼,我們繼續(xù)回到create()源碼中,return代理對(duì)象,至此OKHttpService接口的代理對(duì)象就被創(chuàng)建了,接下來就要使用代理對(duì)象OKHttpService調(diào)用login()方法了。
調(diào)用login()時(shí)我們會(huì)調(diào)用InvocationHandler#invoke()。
ServiceMethod對(duì)象實(shí)例化
一個(gè)ServiceMethod對(duì)象對(duì)應(yīng)了一個(gè)網(wǎng)絡(luò)接口中的方法,該對(duì)象中保存有方法的處理網(wǎng)絡(luò)請(qǐng)求所要用到的各種參數(shù)及方法的屬性注解等,閱讀源碼時(shí)要搞清楚serviceMethod的性質(zhì),這里調(diào)用了loadServiceMethod()我們進(jìn)入方法內(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;
}
同樣,首先會(huì)從緩存中獲取對(duì)象,為null才會(huì)創(chuàng)建實(shí)例對(duì)象,也是一個(gè)單例對(duì)象,在Builer()中會(huì)將解析method一些信息(參數(shù),注解,參數(shù)注解)和retrofit對(duì)象中的屬性,并保存到serviceMethod對(duì)象中。
延伸知識(shí)點(diǎn)(繼續(xù)深追源碼):ServiceMethod不僅存儲(chǔ)了method(也就是login()方法)的參數(shù),屬性等,還存儲(chǔ)有各種適配器,轉(zhuǎn)換器,和http協(xié)議要求的一些相關(guān)check,需要結(jié)合http相關(guān)的知識(shí)來理解。這里直接給結(jié)論,就不繼續(xù)追了。
HttpServiceMethod#invoke
@Override final @Nullable ReturnT invoke(Object[] args) {
//創(chuàng)建一個(gè)網(wǎng)絡(luò)請(qǐng)求器,所以說Retrofit底層默認(rèn)是使用okhttp實(shí)現(xiàn)的
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
//將okhttpcall對(duì)象與網(wǎng)絡(luò)請(qǐng)求適配器進(jìn)行綁定
return adapt(call, args);
}
不難看出,它創(chuàng)建了個(gè)OkHttpCall對(duì)象,retrofit2#OkHttpCall重寫了execute()和enqueue方法等,在隨后的網(wǎng)絡(luò)請(qǐng)求適配器調(diào)用中,就會(huì)執(zhí)行此方法來通過OkHttp請(qǐng)求訪問網(wǎng)絡(luò)
adapt(call, args)
將創(chuàng)建的okHttpCall對(duì)象與serviceMethod中的網(wǎng)絡(luò)請(qǐng)求適配器適配,內(nèi)部return callAdapter.adapt(call);而此callAdapter還記得在哪獲取的?
它是在serviceMethod.loadServiceMethod(method)內(nèi)的createCallAdapter()中選擇的,所以這里的引用是之前選擇的網(wǎng)絡(luò)請(qǐng)求適配器類對(duì)象的adapt(),我們就先看一下它默認(rèn)的網(wǎng)絡(luò)請(qǐng)求適配器也就是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)時(shí),其實(shí)(默認(rèn))調(diào)用了此處的adapt()方法,返回一個(gè)call對(duì)象。
小小整理一下:
當(dāng)客戶端調(diào)用login()方法時(shí),是使用的Proxy.newProxyInstance()返回的代理實(shí)例對(duì)象httpService去調(diào)用的,并且會(huì)回調(diào)InvocationHandler中的invoke()方法,執(zhí)行代理操作,最后通過adapt()返回一個(gè)call對(duì)象。
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是在實(shí)例化ExecutorCallbackCall時(shí)傳遞的第二個(gè)參數(shù),對(duì)象為OkHttpCall,也就是說這里enqueue()又委托給了OkHttpCall來執(zhí)行
this.delegate.enqueue(new Callback<T>() {
public void onResponse(Call<T> call, Response<T> response) {
//在Android環(huán)境中運(yùn)行callbackExecutor默認(rèn)為MainThreadExecutor,當(dāng)網(wǎng)絡(luò)請(qǐng)求成功,執(zhí)行切回到主線程中,回調(diào)客戶端的callback對(duì)象的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) {
//失敗同樣也會(huì)切換到主線程去回調(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的時(shí)候返回了一個(gè)Call,然后調(diào)用enqueue,我們就能看的出就是調(diào)用的這里(默認(rèn)),其實(shí)內(nèi)部調(diào)用的是delegate.enqueue(),也就是我們上文提到過得OkHttpCall的enqueue,調(diào)用okhttp3完成請(qǐng)求,拿到回調(diào)并且處理Response回調(diào)。
ExecutorCallbackCall.this.callbackExecutor
這里其實(shí)還有個(gè)這個(gè)東西需要說明下,callbackExecutor默認(rèn)是個(gè)啥,這里我們就可以追到
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)用接口的實(shí)現(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)建了個(gè)RequestBuilder,對(duì)一些屬性進(jìn)行了賦值,接著看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去請(qǐng)求,回調(diào)處理轉(zhuǎn)換類型。這里就不再細(xì)分下去了。對(duì)于OkHttp的原理感興趣的可以看我之前的博客。
總結(jié)一下上面的流程:
這里首先根據(jù)serviceMethod中關(guān)于login()方法的屬性以及解析的注解信息創(chuàng)建request請(qǐng)求對(duì)象,最后通過return callFactory.newCall(requestBuilder.build());
callFactory默認(rèn)是OkHttpClient,我們就不在深入展示了,最終在其內(nèi)部返回的是一個(gè)RealCall,有興趣的可以進(jìn)去了解一下OkHttpClient源碼,到了這里,Retrofit的網(wǎng)絡(luò)請(qǐng)求底層便顯露在我們眼前,從這里我們就可以看到,Retrofit使用的網(wǎng)絡(luò)底層為OkHttp
接下來退回到enqueue()方法體內(nèi),之后調(diào)用call(RealCall)對(duì)象的enqueue()來處理網(wǎng)絡(luò)請(qǐng)求了,至于之后的事情,就是OkHttp底層要做的了。
最后我們使用RealCall調(diào)用enqueue()傳入的Callback對(duì)象,Callback的onResponse通過parseResponse()完成數(shù)據(jù)轉(zhuǎn)換。成功回調(diào)onResponse,失敗回調(diào)onFailure(),最后客戶端就可以看到網(wǎng)絡(luò)的訪問狀況了。