本文主要用于自我學習和交流,如有錯誤歡迎指正,不勝感激
先看一下我們通常的使用方法
// 1 初始化Retrofit,設置相關參數(shù)
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
// 2 通過動態(tài)代理創(chuàng)建解析出定義API接口中的方法和注解參數(shù),并創(chuàng)建方法實例
GitHubService service = retrofit.create(GitHubService.class);
Call<List<Repo>> repos = service.listRepos("octocat"); // 此處會執(zhí)行動態(tài)代理InvokeHandler的invoke方法
// 3 最終調(diào)用執(zhí)行方法,實際是調(diào)用的OkHttp3的網(wǎng)絡請求,這里會在下一篇文章的解析
repos.enqueue(new Callback<List<Repo>>() {
@Override
public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {
}
@Override
public void onFailure(Call<List<Repo>> call, Throwable t) {
}
})
一、Retrofit初始化
==建造者模式==,使用Builder來創(chuàng)建復雜對象Retrofit
Builder(Platform platform) {
this.platform = platform;
// 添加了默認的轉(zhuǎn)換器工廠
converterFactories.add(new BuiltInConverters());
}
public Builder() {
// 無參構(gòu)造方法,自動獲取平臺來初始化Android,Java8
this(Platform.get());
}
我們主要看一下Retrofit.Builder的==build==方法
/**
* Create the {@link Retrofit} instance using the configured values.
* <p>
* Note: If neither {@link #client} nor {@link #callFactory} is called a default {@link
* OkHttpClient} will be created and used.
* 通過配置創(chuàng)建Retrofit實例,如果沒有給Retrofit設置client或者callFactory,
* 那么會創(chuàng)建并使用默認的OkHttpClient
*/
public Retrofit build() {
// 1.1 檢驗baseUrl是否為空
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
// 1.2 獲取執(zhí)行網(wǎng)絡請求調(diào)用call的callFactory,如果沒有則會使用默認的OkHttpClient
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
// 1.3 獲取默認的回調(diào)執(zhí)行器,沒有設置會使用默認平臺的執(zhí)行器,主要用于執(zhí)行call中返回的execute,request,enqueue等方法
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// 1.4 制作適配器的防御副本并添加默認的呼叫適配器。
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// 1.5 制作轉(zhuǎn)換器的防御副本
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
// 1.6 使用上述參數(shù)創(chuàng)建retrofit對象
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
二、retrofit創(chuàng)建接口實例
下面我們先分析一下create中進行的操作
@SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
public <T> T create(final Class<T> service) {
// 2.1 校驗傳入的參數(shù)是否是interface類型
Utils.validateServiceInterface(service);
// 這里validateEagerly默認初始化為false
if (validateEagerly) {
eagerlyValidateMethods(service);
}
// 2.2 使用動態(tài)代理,解析接口方法的注解和申明字段,并創(chuàng)建傳入接口的實例
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, @Nullable Object[] args)
throws Throwable {
// 如果是繼承自父類Object的方法
// 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);
}
// 步驟一 :Service接口上申明的方法, 這里會解析方法的注解,參數(shù)和返回值,并根據(jù)相關的信息找到對應的轉(zhuǎn)換器Converter和CallAdapter,這些信息都將保存在ServiceMethod中,最后將方法參數(shù)和ServiceMethod存入OkHttpCall中
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
// 將OkHttpCall轉(zhuǎn)換成對應平臺的Call,Android -> ExecutorCallAdapterFactory.ExecutorCallbackCall, Java8 ->DefaultCallAdapterFactory.new CallAdapter()
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
三、執(zhí)行網(wǎng)絡請求
Java動態(tài)代理就會攔截被調(diào)用的Java方法,然后解析這個Java方法的注解,最后生成Request由OkHttp發(fā)送,最終轉(zhuǎn)化為對應平臺的CallAdapter返回給調(diào)用者,這里就是動態(tài)代理在Retrofit中的精髓所在
先分析下核心的步驟一,通過動態(tài)代理拿到接口方法Method method和其參數(shù)Object[] args,下面我們具體的看一下==ServiceMethod.loadServiceMethod==中具體進行了哪些操作。
ServiceMethod<?, ?> loadServiceMethod(Method method) {
// 從緩存中查看是否解析過該方法
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
// 緩存中沒有的話,同步執(zhí)行解析方法,并將解析接過存入緩存中
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
// Builder構(gòu)造方法,獲取了方法的注解,參數(shù)類型,參數(shù)注解
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
==ServiceMethod==是ServiceMethod中核心的方法,需要詳細的分析
public ServiceMethod build() {
// 1.創(chuàng)建出調(diào)用Adapter,并獲取響應類型
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?");
}
// 2. 根據(jù)初始化Retrofit時候設置的轉(zhuǎn)化器和默認的轉(zhuǎn)化器BuildInConverter,創(chuàng)建對應方法響應的converter,當有多個符合條件的轉(zhuǎn)化器時,會選擇List中第一個符合條件的converter
responseConverter = createResponseConverter();
// 3. 轉(zhuǎn)化接口方法注解,
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
......
// 4. 解析方法參數(shù)注解,并存儲在ParameterHandler中
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);
}
......
// 最終把Builder中的數(shù)據(jù)存入到ServiceMethod中
return new ServiceMethod<>(this);
}
作為Retrofit中經(jīng)典的轉(zhuǎn)換器==Converter==和調(diào)用適配器==CallAdapter==,會單獨的進行詳細的說明,這里大家能看懂主流程即可
private CallAdapter<T, R> createCallAdapter() {
// 1. 獲取方法的返回值類型
Type returnType = method.getGenericReturnType();
// 2. 校驗是否有不可取類型的返回類型,具體的泛型相關的知識我們單獨將
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.");
}
// 3. 獲取方法注解
Annotation[] annotations = method.getAnnotations();
try {
//noinspection unchecked
// 4. 查找對應的CallAdapter
return (CallAdapter<T, R>) 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);
}
}
繼續(xù)分析Retrofit的callAdapter方法,這里傳入了我們的返回值類型和方法的注解
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
// 查找出合適的調(diào)用適配器,Android默認的是
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
checkNotNull(returnType, "returnType == null");
checkNotNull(annotations, "annotations == null");
// skipPast為null,所以start = 0, 默認adapterFactories中僅存在Android 平臺的ExecutorCallAdapterFactory
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;
}
}
......
// 構(gòu)建報錯信息,并throw
throw new IllegalArgumentException(builder.toString());
}
繼續(xù)研究下ExecutorCallAdapterFactory
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
// 獲取返回類型的原始類型,如果不是Call返回空, 一般我們定義接口Interface的返回值:Call
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call<Object> adapt(Call<Object> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
從converterFactories中找出合適的轉(zhuǎn)換適配器
public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
return nextResponseBodyConverter(null, type, annotations);
}
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
@Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
checkNotNull(type, "type == null");
checkNotNull(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;
}
}
轉(zhuǎn)換retrofit2.http包下對應的注解頭信息,請求方式、請求Header、請求體數(shù)據(jù)類型MIME1
private void parseMethodAnnotation(Annotation annotation) {
if (annotation instanceof DELETE) {
parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
} else if (annotation instanceof GET) {
parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
} else if (annotation instanceof HEAD) {
parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
if (!Void.class.equals(responseType)) {
throw methodError("HEAD method must use Void as response type.");
}
} else if (annotation instanceof PATCH) {
parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
} else if (annotation instanceof POST) {
parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
} else if (annotation instanceof PUT) {
parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
} else if (annotation instanceof OPTIONS) {
parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
} else if (annotation instanceof HTTP) {
HTTP http = (HTTP) annotation;
parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
} else if (annotation instanceof retrofit2.http.Headers) {
String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
if (headersToParse.length == 0) {
throw methodError("@Headers annotation is empty.");
}
headers = parseHeaders(headersToParse);
} else if (annotation instanceof Multipart) {
if (isFormEncoded) {
throw methodError("Only one encoding annotation is allowed.");
}
isMultipart = true;
} else if (annotation instanceof FormUrlEncoded) {
if (isMultipart) {
throw methodError("Only one encoding annotation is allowed.");
}
isFormEncoded = true;
}
}
轉(zhuǎn)化http方法和路徑
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
if (this.httpMethod != null) {
throw methodError("Only one HTTP method is allowed. Found: %s and %s.",
this.httpMethod, httpMethod);
}
// 設置請求方式(POST,GET,PUT等)和是是否有請求體
this.httpMethod = httpMethod;
this.hasBody = hasBody;
if (value.isEmpty()) {
return;
}
// 檢查url的相對路徑?后是否包含有{id}來動態(tài)的查詢的請求串,如果有拋出異常,uurl中使用動態(tài)的查詢替換可以使用@Query,而不是{}方式
// Get the relative URL path and existing query string, if present.
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("URL query string \"%s\" must not have replace block. "
+ "For dynamic query parameters use @Query.", queryParams);
}
}
// 設置請求相對路徑和請求路徑中的需要動態(tài)替換的參數(shù)
this.relativeUrl = value;
this.relativeUrlParamNames = parsePathParameters(value);
}
總結(jié)上面的步驟
- 找到接口方法對應的轉(zhuǎn)化器converter
- 找到接口方法對應的調(diào)用適配器CallAdapter
- 解析接口方法的注解,獲取對應的請求方式,請求相對路徑,路徑上動態(tài)的路徑參數(shù)
- 解析接口方法的參數(shù),獲取對應的注解
- 將請求包裝成OkHttpCall,并轉(zhuǎn)化成對應平臺的類型,最后調(diào)用serviceMethod.callAdapter.adapt(okHttpCall)
- 最后當我們調(diào)用adapter的excute或enqueue時,交由代理類okHttpCall來完成
主要調(diào)用過程核心類
- Retrofit
- Retrofit.Builder
-
==MethodService==
- MethodService.Builder
- CallAdapter.Factory
- ExecutorCallAdapterFactory (Android平臺)
- DefaultCallAdapterFactory (默認、Java8)
- Converter.Factory
- BuiltInConverters
- Call
- OkHttpCall
- ExecutorCallbackCall
關于OkHttp相關的操作,我們將在下一篇文章進行分析, 動態(tài)代理過程中涉及到很多的泛型和Method、Type的使用,這些也會逐步更新
本文主要用于自我學習和交流,如有錯誤歡迎指正,不勝感激