我們雖然窮劈彪,但是不能說謊,也不能打人顶猜,不是我們的東西粉臊,我們不能拿,要好好讀書驶兜,長(zhǎng)大要做個(gè)對(duì)社會(huì)有用的人扼仲。”——《長(zhǎng)江7號(hào)》
前言
本文從源碼角度分析Retrofit的工作流程抄淑,源碼基于2.7.2屠凶。并以一個(gè)例子來說明Retrofit的使用流程和源碼實(shí)現(xiàn)。
Retrofit的原理
Retrofit充當(dāng)了一個(gè)適配器(Adapter)的角色:將一個(gè)Java接口方法和注釋翻譯成一個(gè)Http請(qǐng)求肆资,然后用OkHttp去發(fā)送這個(gè)請(qǐng)求矗愧。實(shí)現(xiàn)這一功能需要通過動(dòng)態(tài)代理。
代理對(duì)象攔截真實(shí)對(duì)象的方法調(diào)用郑原,在真實(shí)對(duì)象調(diào)用前/后實(shí)現(xiàn)自己的邏輯調(diào)用
Retrofit的使用流程
第一步:Retrofit的創(chuàng)建過程
1.1 創(chuàng)建請(qǐng)求接口
public interface GitHubService{
@GET("user/{user}/repos")
Call<List<Integer>> listRepos(@Path("user") String user);
}
1.2 構(gòu)建一個(gè) Retrofit實(shí)例
通過 create 方法生成 GitHubService的一個(gè)實(shí)現(xiàn)唉韭。
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
//.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
//.addConverterFactory(GsonConverterFactory.create()).
.build();
至此,我們的Retrofit實(shí)例就創(chuàng)建成功了犯犁,通過代碼可知Retrofit的創(chuàng)建采用了構(gòu)建者模式属愤,我們來看Retrofit.Builder的源碼,其部分源碼如下:
public static final class Builder {
//選擇平臺(tái):Android酸役,java等
private final Platform platform;
//okhttp的Call工廠類,Retrofit的網(wǎng)絡(luò)請(qǐng)求實(shí)現(xiàn)委托給okhttp住诸,此工廠類創(chuàng)建出的Call對(duì)象就為可以執(zhí)行網(wǎng)絡(luò)請(qǐng)求的okhttp3.Call對(duì)象。
private @Nullable okhttp3.Call.Factory callFactory;
//此為上面使用代碼中設(shè)置的baseUrl涣澡,Builder將我們?cè)O(shè)置的url封裝為HttpUrl對(duì)象
private @Nullable HttpUrl baseUrl;
//類型轉(zhuǎn)換工廠列表,用于將返回值轉(zhuǎn)換成想要的對(duì)象
private final List<Converter.Factory> converterFactories = new ArrayList<>();
//CallAdapter工廠列表
private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
//回調(diào)線程池
private @Nullable Executor callbackExecutor;
private boolean validateEagerly;
...
public Builder() {
this(Platform.get());
}
}
上面列出了Retrofit.Builder中比較重要的成員變量及方法贱呐,其中部分含義已經(jīng)在注釋中寫明。其中CallAdapter字面含義“請(qǐng)求適配器”入桂,其具體作用是將網(wǎng)絡(luò)請(qǐng)求返回值封裝成我們想要的形式奄薇,比如經(jīng)常使用的RxJava2CallAdapterFactory便是將返回?cái)?shù)據(jù)形式封裝成Flowable對(duì)象來方便進(jìn)行流式編程,我們也可以自定義CallAdapter,不在本位重點(diǎn)討論范圍之內(nèi)抗愁。先來看Builder() 方法馁蒂,其只是簡(jiǎn)單調(diào)用了Platform.get()方法呵晚,Platform.get()方法源碼如下:
class Platform {
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
return new Platform(true);
}
...
}
Platform的get方法最終調(diào)用的是findPlatform方法,根據(jù)不同的運(yùn)行平臺(tái)來提供不同的線程池远搪。由此可見Builder()方法實(shí)際上就行選擇了一下平臺(tái)。
再來看Builder類中converterFactories和callAdapterFactories相關(guān)的設(shè)置方法addCallAdapterFactory()和addConverterFactory()其源碼如下:
/** Add converter factory for serialization and deserialization of objects. */
public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(Objects.requireNonNull(factory, "factory == null"));
return this;
}
/**
* Add a call adapter factory for supporting service method return types other than {@link
* Call}.
*/
public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
callAdapterFactories.add(Objects.requireNonNull(factory, "factory == null"));
return this;
}
可見這兩個(gè)方法只是簡(jiǎn)單的將我們自定義的對(duì)象分別加入到對(duì)應(yīng)列表中逢捺。
繼續(xù)來看Build模式的最后一步.build()方法谁鳍,源碼如下:
public Retrofit build() {
//1這一句告訴我們,baseUrl 是必不可少的劫瞳。
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
//2這里如果你沒配置 callFactory , 會(huì)默認(rèn)配置為 OkHttpClient
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
//3
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
//4沒配置callbackExecutor的話倘潜,會(huì)默認(rèn)配置為 Platform 的 defaultCallbackExecutor
callbackExecutor = platform.defaultCallbackExecutor();
}
//5這里會(huì)把你所配置的 CallAdapter.Factory 加到 List 里去,最后把 Platform 默認(rèn)的 defaultCallAdapterFactory加到 List 的最后邊
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
//6這里一樣會(huì)把你配置的 Converter.Factory 加到 List 里去志于,但是會(huì)把一個(gè) BuiltInConverters 加到第一個(gè)涮因,再將platform.defaultConverterFactories()加到最后一個(gè),請(qǐng)注意這點(diǎn)伺绽。
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories = new ArrayList<>(
1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
// 先添加BuiltInConverters. 這樣不僅防止覆蓋其行為并且可以確保使用的所有類型的轉(zhuǎn)換器正確行為养泡。
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
//7
converterFactories.addAll(platform.defaultConverterFactories());
//8最后返回一個(gè) Retrofit 對(duì)象
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
部分代碼作用注釋已經(jīng)給出,通過源碼我們可以知道:
- 注釋1處說明我們構(gòu)建Retrofit對(duì)象時(shí)baseUrl參數(shù)是必傳的奈应,不然會(huì)報(bào)出異常澜掩。
- 注釋2和3處說明,如果需要對(duì) OkHttpClient 進(jìn)行設(shè)置杖挣,則可以構(gòu)建 OkHttpClient 對(duì)象肩榕,然后調(diào)用callFactory()方法將設(shè)置好的OkHttpClient傳進(jìn)去。如果沒有設(shè)置callFactory惩妇,則直接創(chuàng)建 OkHttpClient株汉。
- 注釋4處的callbackExecutor即回調(diào)線程池,作用是將回調(diào)傳遞到 UI 線程歌殃,我們可以通過callbackExecutor()方法設(shè)置乔妈,一般我們使用默認(rèn)值即可。
下面我們對(duì)其中幾處進(jìn)行進(jìn)一步分析:
先來看看注釋4處的platform.defaultCallbackExecutor()是什么氓皱,通過前面的build()方法分析可知其主要會(huì)根據(jù)平臺(tái)返回一個(gè)platform對(duì)象褒翰,因此在android環(huán)境下會(huì)返回一個(gè)Android()對(duì)象。其源碼如下:
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);
}
}
}
可見android環(huán)境下構(gòu)建Retrofit對(duì)象時(shí)默認(rèn)的CallbackExecutor對(duì)象為MainThreadExecutor匀泊。
注釋5處platform.defaultCallAdapterFactories(callbackExecutor)又是什么呢优训,跟蹤其源碼如下:
List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
@Nullable Executor callbackExecutor) {
DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
return hasJava8Types
? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
: singletonList(executorFactory);
}
可見其默認(rèn)為DefaultCallAdapterFactory對(duì)象轉(zhuǎn)化的列表。
注釋7處platform.defaultConverterFactories()的源碼為:
List<? extends Converter.Factory> defaultConverterFactories() {
return hasJava8Types
? singletonList(OptionalConverterFactory.INSTANCE)
: emptyList();
}
可見其為空列表各聘。
由注釋8可知build() 方法執(zhí)行完時(shí)我們會(huì)得到一個(gè)Retrofit對(duì)象揣非。其構(gòu)造時(shí)將converterFactories和callAdapterFactories封裝為了“只讀”列表。
第二步:創(chuàng)建網(wǎng)絡(luò)請(qǐng)求接口實(shí)例
得到Retrofit對(duì)象和前面定義好的請(qǐng)求接口后我們就可以創(chuàng)建網(wǎng)絡(luò)請(qǐng)求接口實(shí)例了躲因,具體代碼如下:
GitHubService service = retrofit.create(GitHubService.class);
這里便體現(xiàn)了Retrofit的核心功能:將一個(gè)Java接口翻譯成一個(gè)Http請(qǐng)求早敬,前面原理部分說過實(shí)現(xiàn)這一功能需要通過動(dòng)態(tài)代理忌傻。下面我們具體分析源碼:
public <T> T create(final Class<T> service) {
//檢驗(yàn)是否是接口及網(wǎng)絡(luò)接口方法預(yù)加載
validateServiceInterface(service);
//使用動(dòng)態(tài)代理獲取請(qǐng)求接口的所有接口注解配置,并且創(chuàng)建網(wǎng)絡(luò)請(qǐng)求接口實(shí)例
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);
}
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
可見搞监,其會(huì)先去執(zhí)行validateServiceInterface(service)方法水孩,跟蹤源碼如下:
private void validateServiceInterface(Class<?> service) {
if (!service.isInterface()) {
throw new IllegalArgumentException("API declarations must be interfaces.");
}
Deque<Class<?>> check = new ArrayDeque<>(1);
check.add(service);
while (!check.isEmpty()) {
Class<?> candidate = check.removeFirst();
if (candidate.getTypeParameters().length != 0) {
StringBuilder message = new StringBuilder("Type parameters are unsupported on ")
.append(candidate.getName());
if (candidate != service) {
message.append(" which is an interface of ")
.append(service.getName());
}
throw new IllegalArgumentException(message.toString());
}
Collections.addAll(check, candidate.getInterfaces());
}
//1
if (validateEagerly) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
loadServiceMethod(method);
}
}
}
}
根據(jù)源碼可知該方法前面主要做了一些校驗(yàn)工作,我們重點(diǎn)關(guān)注項(xiàng)目注釋1處的邏輯琐驴,這里用到了我們一直未說明的validateEagerly參數(shù)俘种,我們看看其作用是什么,根據(jù)源碼可知绝淡,其邏輯為遍歷前面定義好的網(wǎng)絡(luò)接口方法宙刘,然后回去執(zhí)行l(wèi)oadServiceMethod(method)方法,跟蹤源碼如下:
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;
}
這里我們看到一個(gè)serviceMethodCache對(duì)象牢酵,serviceMethodCache是Retrofit比Retrofit.Builder()多出來的成員變量悬包,跟蹤源碼:
public final class Retrofit {
private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
...
}
ServiceMethod的源碼:
abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(method,
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError(method, "Service methods cannot return void.");
}
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
abstract @Nullable T invoke(Object[] args);
}
可見ServiceMethod為一個(gè)抽象類,serviceMethodCache 為一個(gè)線程安全的馍乙、支持高效并發(fā)的HashMap布近,Key 是 Method,Value 是 ServiceMethod丝格。Method 就是上面接口中定義的方法吊输,而這個(gè)方法中有很多注解,@GET铁追、@Path 等等季蚂,ServiceMethod是將接口定義的方法和注解封裝后的對(duì)象。而變量名帶個(gè) Cache 說明琅束,會(huì)把這個(gè) Method 對(duì)應(yīng)的 ServiceMethod緩存起來扭屁。
由此可見validateServiceInterface(Class<?> service) 方法中注釋1部分整理邏輯為循環(huán)取出定義好接口中的 Method ,接著調(diào)用 loadServiceMethod 涩禀。 loadServiceMethod 里面會(huì)根據(jù) Method 生成一個(gè) ServiceMethod料滥,然后存入 serviceMethodCache ,所以那 validateEagerly 變量是用于正如其名字判斷是否需要提前驗(yàn)證解析的艾船。如果為true葵腹,會(huì)提前把接口中每個(gè)方法進(jìn)行解析得到一個(gè) ServiceMethod 對(duì)象,然后存入緩存中屿岂。
接著回到Retrofit.create()方法后面的代碼部分践宴,在執(zhí)行完 validateServiceInterface(service)方法之后會(huì)使用動(dòng)態(tài)代理獲取請(qǐng)求接口的所有接口注解配置,并且創(chuàng)建并返回T類型的網(wǎng)絡(luò)請(qǐng)求接口實(shí)例即GitHubService爷怀。
第三步:創(chuàng)建Call對(duì)象
得到網(wǎng)絡(luò)請(qǐng)求接口實(shí)例后阻肩,我們就可以通過動(dòng)態(tài)代理的方式去調(diào)用其中的方法,將其轉(zhuǎn)換成對(duì)應(yīng)的網(wǎng)絡(luò)請(qǐng)求的Call對(duì)象實(shí)例了运授。具體示例代碼如下:
Call<List<Integer>> repos = service.listRepos("octocat");
service為前面Retrofit類create()方法創(chuàng)建的接口api的動(dòng)態(tài)代理對(duì)象烤惊,所以調(diào)用其中方法比如service.listRepos("octocat")時(shí)會(huì)觸發(fā)代理對(duì)象上的invoke方法乔煞,再來看Retrofit類create()方法中復(fù)寫的invoke()的源碼:
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 {
// 如果是Object方法直接執(zhí)行
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//此處為java8方法,android環(huán)境下忽略
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//動(dòng)態(tài)解析網(wǎng)絡(luò)接口方法并返回
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
通過源碼可知其最終會(huì)調(diào)用loadServiceMethod(method).invoke(args != null ? args : emptyArgs)方法并返回柒室,其中l(wèi)oadServiceMethod(method)前面我們已經(jīng)提到過渡贾,其主要作用就是解析定義好的網(wǎng)絡(luò)接口,將其中的方法和注釋解析并封裝成一個(gè)ServiceMethod對(duì)象并緩存到Map中⌒塾遥現(xiàn)在我們?cè)偕钊肴ジM(jìn)其中的源碼邏輯看看它都具體做了哪些工作空骚,loadServiceMethod(Method method) 源碼如下:
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;
}
當(dāng)我們不能從緩存的Map中找到對(duì)應(yīng)方法的緩存時(shí)會(huì)調(diào)用ServiceMethod.parseAnnotations(this, method)方法,其源碼如下:
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
//1
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(method,
"Method return type must not include a type variable or wildcard: %s", returnType);
}
//返回值類型不能為空
if (returnType == void.class) {
throw methodError(method, "Service methods cannot return void.");
}
//2
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
注釋1中可見方法會(huì)先創(chuàng)建一個(gè)RequestFactory對(duì)象不脯,通過它的名字我們猜想到它應(yīng)該是用來構(gòu)建網(wǎng)絡(luò)請(qǐng)求Request對(duì)象的府怯,我們來看看這個(gè)RequestFactory的源碼:
final class RequestFactory {
//調(diào)用parseAnnotations方法最終會(huì)通過構(gòu)建者模式創(chuàng)建一個(gè)RequestFactory對(duì)象
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
private final Method method;
private final HttpUrl baseUrl;
final String httpMethod;
private final @Nullable String relativeUrl;
private final @Nullable Headers headers;
private final @Nullable MediaType contentType;
private final boolean hasBody;
private final boolean isFormEncoded;
private final boolean isMultipart;
private final ParameterHandler<?>[] parameterHandlers;
final boolean isKotlinSuspendFunction;
...
//該方法用于創(chuàng)建一個(gè)okhttp3的網(wǎng)絡(luò)請(qǐng)求對(duì)象Request用于具體實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求
okhttp3.create(Object[] args) throws IOException {
...
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl,
headers, contentType, hasBody, isFormEncoded, isMultipart);
List<Object> argumentList = new ArrayList<>(argumentCount);
for (int p = 0; p < argumentCount; p++) {
argumentList.add(args[p]);
handlers[p].apply(requestBuilder, args[p]);
}
return requestBuilder.get()
.tag(Invocation.class, new Invocation(method, argumentList))
.build();
}
/**
* 檢查接口方法上的注釋以構(gòu)造可重用的服務(wù)方法刻诊。 這個(gè)
*可能需要繁重的反射機(jī)制防楷,因此每個(gè)服務(wù)方法最好只構(gòu)建一次
*并重用。 生成器不能重復(fù)使用则涯。
*/
static final class Builder {
// Upper and lower characters, digits, underscores, and hyphens, starting with a character.
private static final String PARAM = "[a-zA-Z][a-zA-Z0-9_-]*";
private static final Pattern PARAM_URL_REGEX = Pattern.compile("\\{(" + PARAM + ")\\}");
private static final Pattern PARAM_NAME_REGEX = Pattern.compile(PARAM);
final Retrofit retrofit;
final Method method;
//方法注解數(shù)組
final Annotation[] methodAnnotations;
//參數(shù)注解二位數(shù)組
final Annotation[][] parameterAnnotationsArray;
//參數(shù)類型數(shù)組
final Type[] parameterTypes;
@Nullable String httpMethod;
boolean hasBody;
boolean isFormEncoded;
boolean isMultipart;
@Nullable String relativeUrl;
@Nullable Headers headers;
@Nullable MediaType contentType;
...
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
RequestFactory build() {
for (Annotation annotation : methodAnnotations) {
//解析方法的注解
parseMethodAnnotation(annotation);
}
...//忽略一堆網(wǎng)絡(luò)協(xié)議規(guī)則校驗(yàn)
return new RequestFactory(this);
}
//方法主要作用就是解析注解設(shè)置成員變量的值
private void parseMethodAnnotation(Annotation annotation) {
if (annotation instanceof DELETE) {
parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
}
...
isFormEncoded = true;
}
}
//方法主要作用就是解析注解設(shè)置成員變量的值
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
if (this.httpMethod != null) {
throw methodError(method, "Only one HTTP method is allowed. Found: %s and %s.",
this.httpMethod, httpMethod);
}
...
this.relativeUrlParamNames = parsePathParameters(value);
}
//方法主要作用是解析并創(chuàng)建Headers實(shí)例
private Headers parseHeaders(String[] headers) {
Headers.Builder builder = new Headers.Builder();
...
return builder.build();
}
...
}
代碼值列出了部分成員變量复局,了解retrofit使用方法就能見文知意了解參數(shù)含義;列出其中主要的方法并簡(jiǎn)單加以注釋粟判。通過源碼我們了解到這個(gè)類的主要作用就是去解析第一步創(chuàng)建好的網(wǎng)絡(luò)請(qǐng)求接口中的方法和注解最終將其轉(zhuǎn)換成okhttp3的網(wǎng)絡(luò)請(qǐng)求Request對(duì)象亿昏。
再回到ServiceMethod類的parseAnnotations(Retrofit retrofit, Method method) 中去,再其中注釋1解析網(wǎng)絡(luò)接口并創(chuàng)建好request對(duì)象后又在注釋2處調(diào)用了HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory)方法档礁,并將其傳了進(jìn)去角钩。繼續(xù)跟進(jìn)源碼:
/** Adapts an invocation of an interface method into an HTTP call. */
abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
/**
* Inspects the annotations on an interface method to construct a reusable service method that
* speaks HTTP. This requires potentially-expensive reflection so it is best to build each service
* method only once and reuse it.
*/
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
...
//1
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
...
//2
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
//此處默認(rèn)為callFactory = new OkHttpClient();
okhttp3.Call.Factory callFactory = retrofit.callFactory;
if (!isKotlinSuspendFunction) {
//3
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<ResponseT>>) callAdapter);
} else {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForBody<>(requestFactory,
callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
continuationBodyNullable);
}
}
}
忽略koltlin協(xié)程相關(guān)功能,重點(diǎn)關(guān)注代碼流程呻澜,在注釋1調(diào)用createCallAdapter(retrofit, method, adapterType, annotations)方法递礼,跟蹤發(fā)現(xiàn)它又會(huì)調(diào)用retrofit.nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,Annotation[] annotations)方法:
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
...
int start = callAdapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
//1
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
...
}
該方法會(huì)循環(huán)遍歷我們之前設(shè)置好的callAdapterFactories并注釋1處調(diào)用其get()方法,由于我們?yōu)轱@示指定CallAdapterFactory前面已經(jīng)分Retrofit默認(rèn)會(huì)設(shè)置為DefaultCallAdapterFactory羹幸,那就來看看其get()方法源碼:
@Override public @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit) {
...
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);
}
};
}
可見其會(huì)返回一個(gè)CallAdapter對(duì)象脊髓。其源碼先不作分析,接著回到HttpServiceMethod的parseAnnotations源碼注釋2處栅受,此處調(diào)用createResponseConverter ()創(chuàng)建一個(gè)Converter對(duì)象将硝,其內(nèi)部流程與callAdapter的創(chuàng)建類似這里就不再做分析了,只是作用為將返回值類型通過此處創(chuàng)建的Conver對(duì)象轉(zhuǎn)化為我們想要的數(shù)據(jù)類型屏镊。比如我們?cè)賱?chuàng)建Retrofit實(shí)例時(shí)經(jīng)常設(shè)置的GsonConverterFactory就是講返回值通過gson解析成想要的實(shí)體類依疼。
接著分析HttpServiceMethod的parseAnnotations源碼的注釋3處,此處調(diào)用new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter)方法而芥,并將之前設(shè)置的參數(shù)全傳遞了進(jìn)去涛贯,來看源碼:
CallAdapted(RequestFactory requestFactory, okhttp3.Call.Factory callFactory,
Converter<ResponseBody, ResponseT> responseConverter,
CallAdapter<ResponseT, ReturnT> callAdapter) {
super(requestFactory, callFactory, responseConverter);
this.callAdapter = callAdapter;
}
HttpServiceMethod(RequestFactory requestFactory, okhttp3.Call.Factory callFactory,
Converter<ResponseBody, ResponseT> responseConverter) {
this.requestFactory = requestFactory;
this.callFactory = callFactory;
this.responseConverter = responseConverter;
}
可見該方法主要邏輯為給自己的成員變量賦值。所以loadServiceMethod()中解析網(wǎng)絡(luò)接口定義并封裝成ServiceMethod對(duì)象時(shí)還做了一下幾件事情:
- 解析網(wǎng)絡(luò)接口定義蔚出,根據(jù)方法和注解創(chuàng)建網(wǎng)絡(luò)請(qǐng)求的request實(shí)例弟翘;
- 根據(jù)我們?cè)O(shè)置的CallFactory設(shè)置okhttp3的call對(duì)象虫腋,默認(rèn)為new OkHttpClient();
- 根據(jù)我們?cè)O(shè)置的CallAdapterFactory創(chuàng)建好calladapter對(duì)象;
- 根據(jù)我們?cè)O(shè)置的ConverterFactory創(chuàng)建網(wǎng)絡(luò)返回值轉(zhuǎn)換converter對(duì)象稀余;
- 將所有上面這些對(duì)象設(shè)置給HttpServiceMethod的成員變量加以管理悦冀,等待后續(xù)使用。
繼續(xù)回到Retrofit的create()通過動(dòng)態(tài)代理重寫的invoke()源碼中睛琳,其最終調(diào)用loadServiceMethod(method).invoke(args != null ? args : emptyArgs)方法通過前面的分析可知其執(zhí)行的是HttpServiceMethod的invoke()方法盒蟆,源碼如下:
@Override final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
方法創(chuàng)建了一個(gè)OkHttpCall對(duì)象,通過其名稱可知其為okhttp實(shí)現(xiàn)的網(wǎng)絡(luò)請(qǐng)求的具體call對(duì)象的封裝师骗。通過起源也可發(fā)現(xiàn)其集成Call類并在內(nèi)部維護(hù)了整套由okhttp3實(shí)現(xiàn)的網(wǎng)絡(luò)請(qǐng)求功能具體實(shí)現(xiàn)及返回?cái)?shù)據(jù)解析parseResponse()方法的實(shí)現(xiàn)其內(nèi)部通過前面創(chuàng)建的convert對(duì)象來解析返回結(jié)果历等。其源碼如下:
final class OkHttpCall<T> implements Call<T> {
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 the response along.
rawResponse = rawResponse.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
int code = rawResponse.code();
if (code < 200 || code >= 300) {
try {
// Buffer the entire body to avoid future I/O.
ResponseBody bufferedBody = Utils.buffer(rawBody);
return Response.error(bufferedBody, rawResponse);
} finally {
rawBody.close();
}
}
if (code == 204 || code == 205) {
rawBody.close();
return Response.success(null, rawResponse);
}
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try {
//通過前面創(chuàng)建好并傳遞過來的converter對(duì)象解析返回值
T body = responseConverter.convert(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
// If the underlying source threw an exception, propagate that rather than indicating it was
// a runtime exception.
catchingBody.throwIfCaught();
throw e;
}
}
}
其中正常網(wǎng)絡(luò)請(qǐng)求的方法為okhttp網(wǎng)絡(luò)請(qǐng)求實(shí)現(xiàn),源碼就不貼了辟癌,不了解okhttp網(wǎng)絡(luò)請(qǐng)求原理的可以去查看我之前發(fā)布的okhttp框架源碼解析寒屯。接著其由調(diào)用了adapt(call, args)方法,通過前面分析知其實(shí)際調(diào)用了其子類CallAdapted的adapt方法黍少,源碼如下:
@Override protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return callAdapter.adapt(call);
}
通過loadServiceMethod()內(nèi)部邏輯的分析第三步可知其實(shí)際調(diào)用的是創(chuàng)建好的calladapter對(duì)象的adapte方法寡夹,這里再重貼一遍上面為分析完的DefaultCallAdapterFactory get()方法創(chuàng)建的calladapter方法的源碼:
@Override public @Nullable CallAdapter<?, ?> get(
...
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);
}
};
}
由代碼可知,其最終又調(diào)用了new ExecutorCallbackCall<>(executor, call)方法厂置,其源碼為:
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
功能為給ExecutorCallbackCall類內(nèi)部成員變量賦值以待后續(xù)執(zhí)行網(wǎng)絡(luò)請(qǐng)求時(shí)使用菩掏。由此我們前面的這行代碼終于分析完了:
Call<List<Integer>> repos = service.listRepos("octocat");
其通過動(dòng)態(tài)代理最終得到了一個(gè)ExecutorCallbackCall對(duì)象實(shí)例。并且通過其成員變量名稱猜想之后的網(wǎng)絡(luò)同步異步請(qǐng)求應(yīng)該是被其delegate成員代理實(shí)現(xiàn)的昵济。請(qǐng)求返回的結(jié)果的線程切換時(shí)由callbackExecutor 處理的智绸。
第四步:通過創(chuàng)建好的由Retrofit封裝的Call對(duì)象來進(jìn)行網(wǎng)絡(luò)通信
Retrofit將Call對(duì)象進(jìn)行了進(jìn)一步封裝,其內(nèi)部交由OkHttpCall這個(gè)實(shí)習(xí)類來通過okhttp具體實(shí)現(xiàn)網(wǎng)絡(luò)通信访忿。
現(xiàn)在以異步請(qǐng)求為例看一看Retrofit網(wǎng)絡(luò)請(qǐng)求的實(shí)現(xiàn)瞧栗,通過起那么分析指導(dǎo)enqueue()的代碼實(shí)現(xiàn)默認(rèn)其實(shí)為ExecutorCallbackCall類的enqueue()方法如下:
@Override public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
// 真正的Call請(qǐng)求確實(shí)由delegate(前面分析的OkHttpCall對(duì)象)去執(zhí)行的
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
// 回調(diào)后 利用 MainThreadExecutor中的 Handler 切換到主線程中去。
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<T> call, final Throwable t) {
callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
}
});
}
可以看到是 delegate 執(zhí)行了 enqueue 操作醉顽,而 delegate 就是我們的 OkHttpCall 沼溜,在 OkHttpCall 里的 enqueue 方法是這樣工作的。通過 okhttp3.Call call = serviceMethod.toCall(args); 構(gòu)建一個(gè)真正執(zhí)行請(qǐng)求的 Call 游添,即把請(qǐng)求交給 okhttp 去完成系草。而構(gòu)建一個(gè) Call 利用到了 ServiceMethod 中的 ParameterHandler 對(duì)象,這個(gè)對(duì)象是用來處理參數(shù)的唆涝。 它會(huì)把具體參數(shù)的值與 RequestBuilder 綁定起來找都。當(dāng)然也用到了 ServiceMethod 自己,ServiceMethod 類似請(qǐng)求響應(yīng)的大管家廊酣。
別忘了拿到響應(yīng)后能耻,在 okhttp3.Callback 中會(huì)去調(diào)用 response = parseResponse(rawResponse); 將響應(yīng)轉(zhuǎn)換成自己想要的格式,即定義的 Converter 。關(guān)于返回值得解析在此就不繼續(xù)解讀了晓猛,因?yàn)椴皇俏覀兇宋牡闹攸c(diǎn)饿幅。
總結(jié)
到此,整個(gè)Retrofit的流程終于走完了戒职。簡(jiǎn)單總結(jié)如下:
- 通過建造者模式構(gòu)建一個(gè)Retrofit實(shí)例栗恩,配置baseUrl,callAdapterFactory(將代理返回的Call對(duì)象轉(zhuǎn)化為其他洪燥,比如Rxjava的Observer)磕秤,converterFactory(結(jié)果的轉(zhuǎn)化器,將請(qǐng)求的結(jié)果轉(zhuǎn)化為特定的對(duì)象時(shí)使用捧韵,比如GsonConverterFactory)市咆。
- 通過Retrofit對(duì)象的create(Class<T> service)方法返回一個(gè)Service的動(dòng)態(tài)代理對(duì)象,在調(diào)用service的方法的時(shí)候再来,就是調(diào)用動(dòng)態(tài)代理的invoke方法蒙兰。
- 調(diào)用代理的invoke方法的時(shí)候,會(huì)將網(wǎng)絡(luò)接口api進(jìn)行解析其弊,解析我們定義的接口方法以及配置的各種注解癞己,最后構(gòu)造成ServiceMethod對(duì)象膀斋,并將結(jié)果緩存起來梭伐。解析過程中會(huì)根據(jù)我們的配置創(chuàng)建接口描述的Request對(duì)象、CallFactory設(shè)置okhttp3的call對(duì)象仰担、calladapter對(duì)象糊识、converter對(duì)象。接著又創(chuàng)建OkHttpCall實(shí)例來管理真正的網(wǎng)絡(luò)實(shí)現(xiàn),然后通過callAdapter轉(zhuǎn)化為用戶希望得到的返回對(duì)象摔蓝,默認(rèn)是直接返回ExecutorCallbackCall對(duì)象赂苗。
- 返回Call對(duì)象之后,我們?cè)僬{(diào)用同步execute或者異步enqueue請(qǐng)求贮尉,方法內(nèi)部會(huì)通過Okhttp實(shí)現(xiàn)的網(wǎng)絡(luò)請(qǐng)求方法拌滋。并根據(jù)上一步創(chuàng)建的converter對(duì)象將返回?cái)?shù)據(jù)解析成我們想要的實(shí)體類豪娜。