前言
Retrofit的核心在于它的create方法中使用了動(dòng)態(tài)代理淑履,在這里面主要是loadServiceMethod方法:
以下代碼基于Retrofit2.5.0(跟2.3.0代碼存在明顯不同)
public <T> T create(final Class<T> service) {
//省略無關(guān)代碼
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 Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
//省略無關(guān)代碼
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
請求方法的解析
首先來看loadServiceMethod方法:
Retrofit.loadServiceMethod(Method method)
private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
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;
}
serviceMethodCache是一個(gè)緩存的Map米苹,這個(gè)方法主要就是執(zhí)行了ServiceMethod.parseAnnotations
先看看返回的類ServiceMethod
這個(gè)方法返回ServiceMethod這個(gè)類:
abstract class ServiceMethod<T> {//抽象類
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {//解析注解
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);//請求工廠初始化
Type returnType = method.getGenericReturnType();//獲取方法的返回類型
//省略無關(guān)代碼
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);//返回解析結(jié)果
}
abstract T invoke(Object[] args);
}
繼續(xù)看RequestFactory.parseAnnotations(retrofit, method):
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
在這里又用到了創(chuàng)建者方法來創(chuàng)建這個(gè)請求工廠公般,進(jìn)入Builder:
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;//當(dāng)前的retrofit實(shí)例
this.method = method;//請求的方法
this.methodAnnotations = method.getAnnotations();//注解
this.parameterTypes = method.getGenericParameterTypes();//參數(shù)的類型集合
this.parameterAnnotationsArray = method.getParameterAnnotations();//參數(shù)的注解集合
}
可以看到這個(gè)創(chuàng)建類里面包含了我們在接口定義的方法的所有信息臼疫,包括注解和參數(shù)择份,再繼續(xù)來看它的build方法做了什么:
RequestFactory build() {
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);//重點(diǎn)1.解析方法上面的注解
}
//省略無關(guān)代碼
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
parameterHandlers[p] = parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p]);//重點(diǎn)2.解析方法的參數(shù)
}
//省略無關(guān)代碼
return new RequestFactory(this);
}
在這里,進(jìn)行了對方法的具體解析烫堤,主要是兩個(gè)步驟
- 解析方法上面的注解parseMethodAnnotation
- 解析方法的請求參數(shù)注解parseParameter
到兩個(gè)方法里面看看:
方法上面的注解
RequestFactory.parseMethodAnnotation
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);
} 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(method, "@Headers annotation is empty.");
}
headers = parseHeaders(headersToParse);
} else if (annotation instanceof Multipart) {
if (isFormEncoded) {
throw methodError(method, "Only one encoding annotation is allowed.");
}
isMultipart = true;
} else if (annotation instanceof FormUrlEncoded) {
if (isMultipart) {
throw methodError(method, "Only one encoding annotation is allowed.");
}
isFormEncoded = true;
}
}
在這里荣赶,看到了熟悉的一幕,我們平常使用Retrofit時(shí)在方法上面使用的@POST和@GET之類的注解鸽斟,就是在這個(gè)方法里面進(jìn)行的解析拔创,這里先做一個(gè)判斷,繼續(xù)調(diào)用parseHttpMethodAndPath
RequestFactory.parseHttpMethodAndPath
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.httpMethod = httpMethod;//請求方法
this.hasBody = hasBody;//是否有請求體
if (value.isEmpty()) {
return;
}
// 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(method, "URL query string \"%s\" must not have replace block. "
+ "For dynamic query parameters use @Query.", queryParams);
}
}
this.relativeUrl = value;//相對請求地址
this.relativeUrlParamNames = parsePathParameters(value);//解析請求鏈接里面的參數(shù)
}
在這里進(jìn)行了關(guān)于請求的方法等相關(guān)屬性的賦值富蓄,最后調(diào)用parsePathParameters解析我們在注解里面?zhèn)魅氲牡刂返膮?shù):
RequestFactory.parsePathParameters
private static final String PARAM = "[a-zA-Z][a-zA-Z0-9_-]*";
private static final Pattern PARAM_URL_REGEX = Pattern.compile("\\{(" + PARAM + ")\\}");
static Set<String> parsePathParameters(String path) {
Matcher m = PARAM_URL_REGEX.matcher(path);
Set<String> patterns = new LinkedHashSet<>();
while (m.find()) {
patterns.add(m.group(1));
}
return patterns;
}
這里應(yīng)該都能看懂剩燥,使用正則表達(dá)式來匹配。
到這里立倍,完成了對方法上面的注解的解析灭红,接下來侣滩,進(jìn)行對方法的參數(shù)的解析:
方法的請求參數(shù)注解
RequestFactory.parseParameter
private ParameterHandler<?> parseParameter(
int p, Type parameterType, @Nullable Annotation[] annotations) {
ParameterHandler<?> result = null;
if (annotations != null) {
for (Annotation annotation : annotations) {
ParameterHandler<?> annotationAction =
parseParameterAnnotation(p, parameterType, annotations, annotation);//參數(shù)解析
//省略無關(guān)代碼
result = annotationAction;
}
}
//省略無關(guān)代碼
return result;
}
返回的ParameterHandler類為參數(shù)的句柄,這里是一個(gè)抽象類变擒,里面有Header君珠,Path,Query等跟我們在參數(shù)前面加的標(biāo)注同名的實(shí)現(xiàn)類赁项。
使用一個(gè)循環(huán)葛躏,來解析每個(gè)參數(shù)的注解,這里調(diào)用了parseParameterAnnotation方法,這個(gè)方法跟剛才解析方法上面的注解parseMethodAnnotation很像悠菜,里面進(jìn)行了很多判斷,在參數(shù)里面可以加的注解很多败富,所以方法太長悔醋,這里看一看我們經(jīng)常用到的GET請求的@Query注解的解析:
RequestFactory.parseParameterAnnotation
//省略無關(guān)代碼
} else if (annotation instanceof Query) {
validateResolvableType(p, type);
Query query = (Query) annotation;
String name = query.value();
boolean encoded = query.encoded();
Class<?> rawParameterType = Utils.getRawType(type);//獲取類型
gotQuery = true;
if (Iterable.class.isAssignableFrom(rawParameterType)) {//是否是集合
if (!(type instanceof ParameterizedType)) {
throw parameterError(method, p, rawParameterType.getSimpleName()
+ " must include generic type (e.g., "
+ rawParameterType.getSimpleName()
+ "<String>)");
}
ParameterizedType parameterizedType = (ParameterizedType) type;
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
Converter<?, String> converter =
retrofit.stringConverter(iterableType, annotations);
return new ParameterHandler.Query<>(name, converter, encoded).iterable();
} else if (rawParameterType.isArray()) {//是否是集合的數(shù)組
Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
Converter<?, String> converter =
retrofit.stringConverter(arrayComponentType, annotations);
return new ParameterHandler.Query<>(name, converter, encoded).array();
} else {//普通類型
Converter<?, String> converter =
retrofit.stringConverter(type, annotations);
return new ParameterHandler.Query<>(name, converter, encoded);
}
} else if (annotation instanceof QueryName) {
//省略無關(guān)代碼
在這個(gè)方法里面進(jìn)行了類型和泛型相關(guān)的判斷,里面都調(diào)用了retrofit.stringConverter方法:
retrofit.stringConverter
public <T> Converter<T, String> stringConverter(Type type, Annotation[] annotations) {
checkNotNull(type, "type == null");
checkNotNull(annotations, "annotations == null");
for (int i = 0, count = converterFactories.size(); i < count; i++) {
Converter<?, String> converter =
converterFactories.get(i).stringConverter(type, annotations, this);
if (converter != null) {
//noinspection unchecked
return (Converter<T, String>) converter;
}
}
// Nothing matched. Resort to default converter which just calls toString().
//noinspection unchecked
return (Converter<T, String>) BuiltInConverters.ToStringConverter.INSTANCE;
}
這個(gè)方法的作用是獲取請求參數(shù)的json解析器兽叮,一個(gè)循環(huán)從converterFactories數(shù)組中依次獲取加入的解析器工廠芬骄,我們在之前創(chuàng)建Retrofit傳入的是GsonConverterFactory,打開這個(gè)類鹦聪,并沒有發(fā)現(xiàn)stringConverter方法账阻,再打開它的父類Converter.Factory,看到了這個(gè)方法:
public @Nullable Converter<?, String> stringConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return null;
}
返回的是空泽本,說明這里不需要使用解析工廠將請求的參數(shù)轉(zhuǎn)化為String淘太。所以直接調(diào)用最后一句
return (Converter<T, String>) BuiltInConverters.ToStringConverter.INSTANCE;
static final class ToStringConverter implements Converter<Object, String> {
static final ToStringConverter INSTANCE = new ToStringConverter();
@Override public String convert(Object value) {
return value.toString();
}
}
返回的是一個(gè)默認(rèn)的轉(zhuǎn)化類,在這個(gè)類的convert方法使用的是類自身的toString來轉(zhuǎn)化规丽。
到此為止蒲牧,就完成了我們在接口中定義的那個(gè)方法的全部解析。
總結(jié)
Retrofit使用了動(dòng)態(tài)代理赌莺,所以每次執(zhí)行我們在接口中定義的方法會(huì)來到動(dòng)態(tài)代理中的invoke方法冰抢,在這里面,又執(zhí)行了loadServiceMethod來實(shí)現(xiàn)對方法的解析艘狭,主要是兩個(gè)步驟:
- 解析方法上面的注解(如@Headers挎扰,@POST,@GET)
- 解析方法的請求參數(shù)前面的注解(如@Query, @Field)