Retrofit源碼解析(四)—ServiceMethod相關分析
標籤(空格分隔): Retrofit源碼 學習筆記
前言
- 以下的相關知識總結是通過慕課網的相關學習和自己的相關看法,如果有需要的可以去查看一下慕課網的相關教學,感覺還可以。
定義一個接口
//看下我們創建的這個接口 這個方法返回一個Call<T>對象
// @GET表示方法是get請求 article/list/latest?page=1表示相對url請求地址 第一部分在baseUrl裏面
//每個方法參數都需要進行註解標誌
@GET("article/list/latest?page=1")
Call<HttpResult<List<TestBean>>> getQiuShiJsonString();
解析create()方法
//這個通過創建的Retrofit的實例創建一個接口服務
TestInterface service =getRetrofit().create(TestInterface.class);
- create方法的定義
Create an implementation of the API endpoints defined by the {@code service} interface.
public <T> T create(final Class<T> service) {
//這個方法邏輯是用來判斷這個service是否合法
Utils.validateServiceInterface(service);
//下面的這個validateEagerly 就是之前的那個標誌 判斷是否是提前解析這個接口
if (validateEagerly) {
//解析在後面
eagerlyValidateMethods(service);
}
//做完上面的判斷驗證之後 接下來就是關鍵地方
//返回了一個網絡接口的動態代理對象 實質就是通過動態代理創建網絡接口實例的
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 {
// If the method is a method from Object then defer to normal invocation.
//如果調用的是Object方法
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//最核心的三行代碼 這個在後面進行講解吧
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
- 如果validateEagerly這個標誌爲true的時候 會提前進入這個方法來驗證這個service和解析他。
private void eagerlyValidateMethods(Class<?> service) {
//判斷使用平臺 android ios java8三個平臺
Platform platform = Platform.get();
//傳遞過去的接口方法進行循環
for (Method method : service.getDeclaredMethods()) {
//可以看出isDefaultMethod()方法是返回false 所以一定會走下面的loadServiceMethod()方法
if (!platform.isDefaultMethod(method)) {
loadServiceMethod(method);
}
}
}
- loadServiceMethod(method)方法查看
ServiceMethod<?, ?> loadServiceMethod(Method method) {
//private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>(); 之前版本是LinkedHashMap() 現在的版本是ConcurrentHashMap
//http://angelbill3.iteye.com/blog/2277062
//這個是通過serviceMethodCache的get方法獲取到緩存的method
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
//如果有這個緩存 那麼就直接返回結果
if (result != null) return result;
//如果緩存中沒有這個數據 鎖機制
synchronized (serviceMethodCache) {
//再次判斷是否有緩存
result = serviceMethodCache.get(method);
if (result == null) {
//根據ServiceMethod的構建者模式創建一個ServiceMethod對象
result = new ServiceMethod.Builder<>(this, method).build();
//把method作爲key value就是result(ServiceMethod)
serviceMethodCache.put(method, result);
}
}
//返回ServiceMethod這個結果
return result;
}
核心的三行代碼
//就是用來獲取到ServiceMethod,比如我們在接口中定義的方法 對應一個接口中定義好的請求方法 比如getCall()方法
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
ServiceMethod類
相關的成員變量
// Upper and lower characters, digits, underscores, and hyphens, starting with a character.
static final String PARAM = "[a-zA-Z][a-zA-Z0-9_-]*";
static final Pattern PARAM_URL_REGEX = Pattern.compile("\\{(" + PARAM + ")\\}");
static final Pattern PARAM_NAME_REGEX = Pattern.compile(PARAM);
//網絡請求工廠 也就是okhttp的網絡請求
final okhttp3.Call.Factory callFactory;
//網絡請求適配器 把call請求適配各個平臺
final CallAdapter<R, T> callAdapter;
//網絡基地址
private final HttpUrl baseUrl;
//數據轉換器
private final Converter<ResponseBody, R> responseConverter;
//網絡請求的http方法 比如get post方法
private final String httpMethod;
//網絡請求的相對地址 和baseUrl拼接起來就是實際地址
private final String relativeUrl;
//請求頭
private final Headers headers;
//網絡請求的http報文的type
private final MediaType contentType;
//三個標誌位
private final boolean hasBody;
private final boolean isFormEncoded;
private final boolean isMultipart;
//方法參數的處理器 比如我們定義的方法 上面的@get和後面的參數
private final ParameterHandler<?>[] parameterHandlers;
可以瞭解到ServiceMethod完全包含了我們訪問網絡的所有的基本信息。
首先看下他的構造函數
//可以看出是傳遞的是一個Builder內部類 所以ServiceMethod也是通過構建者模式來初始化他的成員變量的
ServiceMethod(Builder<R, T> builder) {
}
//可以看出就是通過build來創建的 最後調用build進行創建
ServiceMethod result = new ServiceMethod.Builder<>(this, method).build();
//構造方法
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method; //網絡請求方法
//獲取網絡請求方法中的註解 @GET @POST
this.methodAnnotations = method.getAnnotations();
//獲取網絡請求方法中的參數類型
this.parameterTypes = method.getGenericParameterTypes();
//獲取網絡請求中的註解內容
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
所以通過這個builder方法就能配置好我們ServiceMethod方法的成員變量
我們來看下build方法做了哪些內容吧,因爲最後是調用build方法來完成ServiceMethod的創建
//第一行 創建callAdapter
callAdapter = createCallAdapter();
//第二行 根據網絡請求接口的返回值類型和註解類型從retrofit對象當中獲取這個網絡適配器返回的數據類型
responseType = callAdapter.responseType();
//第三行(異常 檢查的代碼去掉了)
responseConverter = createResponseConverter();
//第四行 這個就是對接口註解類型進行解析
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
//這個就是判斷 接口需要@GET @POST @PUT方式的註解
if (httpMethod == null) {
throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
//獲取到參數註解的長度
int parameterCount = parameterAnnotationsArray.length;
//參數解析器初始化
parameterHandlers = new ParameterHandler<?>[parameterCount];
//開始循環解析
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
//然後通過parseParameter()這個方法來解析參數 通過我們傳入的參數類型和參數的註解內容
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
所以總結的來說就是build方法就是根據我們定義好的請求接口中的返回值類型和方法中的註解來從我們的網絡請求適配器工廠和數據轉換器工廠集合中分別獲取到我們所需要的網絡請求適配器和response數據轉換器,然後根據參數註解去獲取到我們所需要的解析的參數,最後調用parseParameter()方法來解析我們接口中的參數。
- createCallAdapter()方法
//是根據retrofit網絡請求中接口的方法的返回值類型和註解的類型從我們的retrofit對象當中獲取對應的網絡請求適配器
private CallAdapter<T, R> createCallAdapter() {
//獲取網絡請求接口中方法中的返回值類型
Type returnType = method.getGenericReturnType();
。。。。
//獲取註解類型
Annotation[] annotations = method.getAnnotations();
//最終調用retrofit的callAdapter 返回我們的網絡適配器
return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
}
}
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
int start = adapterFactories.indexOf(skipPast) + 1;
//創建callAdapter 遍歷這個callAdapter的工廠集合 尋找合適的工廠
for (int i = start, count = adapterFactories.size(); i < count; i++) {
//然後通過這個工廠的get方法 還有傳入的返回值類型和註解類型 創建我們需要的callAdapter 比如RxJavaCallAdapterFactory
CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
- createResponseConverter方法
//獲取接口中網絡請求方法的註解類型
Annotation[] annotations = method.getAnnotations();
return
//返回一個converter
retrofit.responseBodyConverter(responseType, annotations);
//就是這個方法 傳入接口的返回值類型和註解類型
public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
//
return nextResponseBodyConverter(null, type, annotations);
}
//這個和上述的callAdapter的邏輯有點類似
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
int start = converterFactories.indexOf(skipPast) + 1;
for (int i = start, count = converterFactories.size(); i < count; i++) {
//也就是循環數據轉換工廠的集合 然後通過傳入的返回值類型和註解類型 獲取到適合我們的數據轉換工廠 然後通過這個轉換器responseBodyConver方法獲取我們相應的數據轉換器 在retrofit中默認的是GsonConverter轉換器
Converter<ResponseBody, ?> converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
if (converter != null) {
return (Converter<ResponseBody, T>) converter;
}
}