Android笔记|Retrofit2.5是如何解析在接口类中定义的方法()

前言 Retrofit的核心在于它的create方法中使用了动态代理,在这里面主要是loadServiceMethod方法:

以下代码基于Retrofit2.5.0(跟2.3.0代码存在明显不同)
public T create(final Class 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 Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable { //省略无关代码 return loadServiceMethod(method).invoke(args != null ? args : emptyArgs); } }); }

请求方法的解析 首先来看loadServiceMethod方法:
Retrofit.loadServiceMethod(Method method)
private final Map> 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是一个缓存的Map,这个方法主要就是执行了ServiceMethod.parseAnnotations
先看看返回的类ServiceMethod
这个方法返回ServiceMethod这个类:
abstract class ServiceMethod {//抽象类 static ServiceMethod parseAnnotations(Retrofit retrofit, Method method) {//解析注解 RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method); //请求工厂初始化Type returnType = method.getGenericReturnType(); //获取方法的返回类型 //省略无关代码 return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory); //返回解析结果 }abstract T invoke(Object[] args); }

继续看RequestFactory.parseAnnotations(retrofit, method):
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) { return new Builder(retrofit, method).build(); }

在这里又用到了创建者方法来创建这个请求工厂,进入Builder:
Builder(Retrofit retrofit, Method method) { this.retrofit = retrofit; //当前的retrofit实例 this.method = method; //请求的方法 this.methodAnnotations = method.getAnnotations(); //注解 this.parameterTypes = method.getGenericParameterTypes(); //参数的类型集合 this.parameterAnnotationsArray = method.getParameterAnnotations(); //参数的注解集合 }

可以看到这个创建类里面包含了我们在接口定义的方法的所有信息,包括注解和参数,再继续来看它的build方法做了什么:
RequestFactory build() { for (Annotation annotation : methodAnnotations) { parseMethodAnnotation(annotation); //重点1.解析方法上面的注解 } //省略无关代码 int parameterCount = parameterAnnotationsArray.length; parameterHandlers = new ParameterHandler[parameterCount]; for (int p = 0; p < parameterCount; p++) { parameterHandlers[p] = parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p]); //重点2.解析方法的参数 } //省略无关代码 return new RequestFactory(this); }

在这里,进行了对方法的具体解析,主要是两个步骤
  1. 解析方法上面的注解parseMethodAnnotation
  2. 解析方法的请求参数注解parseParameter
到两个方法里面看看:
方法上面的注解
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时在方法上面使用的@POST和@GET之类的注解,就是在这个方法里面进行的解析,这里先做一个判断,继续调用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); //解析请求链接里面的参数 }

在这里进行了关于请求的方法等相关属性的赋值,最后调用parsePathParameters解析我们在注解里面传入的地址的参数:
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> parsePathParameters(String path) { Matcher m = PARAM_URL_REGEX.matcher(path); Set> patterns = new LinkedHashSet<>(); while (m.find()) { patterns.add(m.group(1)); } return patterns; }

这里应该都能看懂,使用正则表达式来匹配。
到这里,完成了对方法上面的注解的解析,接下来,进行对方法的参数的解析:
方法的请求参数注解
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); //参数解析//省略无关代码result = annotationAction; } }//省略无关代码 return result; }

返回的ParameterHandler类为参数的句柄,这里是一个抽象类,里面有Header,Path,Query等跟我们在参数前面加的标注同名的实现类。
使用一个循环,来解析每个参数的注解,这里调用了parseParameterAnnotation方法,这个方法跟刚才解析方法上面的注解parseMethodAnnotation很像,里面进行了很多判断,在参数里面可以加的注解很多,所以方法太长,这里看一看我们经常用到的GET请求的@Query注解的解析:
RequestFactory.parseParameterAnnotation
//省略无关代码 } 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() + ")"); } ParameterizedType parameterizedType = (ParameterizedType) type; Type iterableType = Utils.getParameterUpperBound(0, parameterizedType); Converter converter = retrofit.stringConverter(iterableType, annotations); return new ParameterHandler.Query<>(name, converter, encoded).iterable(); } else if (rawParameterType.isArray()) {//是否是集合的数组 Class arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType()); Converter converter = retrofit.stringConverter(arrayComponentType, annotations); return new ParameterHandler.Query<>(name, converter, encoded).array(); } else {//普通类型 Converter converter = retrofit.stringConverter(type, annotations); return new ParameterHandler.Query<>(name, converter, encoded); }} else if (annotation instanceof QueryName) { //省略无关代码

在这个方法里面进行了类型和泛型相关的判断,里面都调用了retrofit.stringConverter方法:
retrofit.stringConverter
public Converter stringConverter(Type type, Annotation[] annotations) { checkNotNull(type, "type == null"); checkNotNull(annotations, "annotations == null"); for (int i = 0, count = converterFactories.size(); i < count; i++) { Converter converter = converterFactories.get(i).stringConverter(type, annotations, this); if (converter != null) { //noinspection unchecked return (Converter) converter; } }// Nothing matched. Resort to default converter which just calls toString(). //noinspection unchecked return (Converter) BuiltInConverters.ToStringConverter.INSTANCE; }

这个方法的作用是获取请求参数的json解析器,一个循环从converterFactories数组中依次获取加入的解析器工厂,我们在之前创建Retrofit传入的是GsonConverterFactory,打开这个类,并没有发现stringConverter方法,再打开它的父类Converter.Factory,看到了这个方法:
public @Nullable Converter stringConverter(Type type, Annotation[] annotations, Retrofit retrofit) { return null; }

返回的是空,说明这里不需要使用解析工厂将请求的参数转化为String。所以直接调用最后一句
return (Converter) BuiltInConverters.ToStringConverter.INSTANCE;

static final class ToStringConverter implements Converter { static final ToStringConverter INSTANCE = new ToStringConverter(); @Override public String convert(Object value) { return value.toString(); } }

返回的是一个默认的转化类,在这个类的convert方法使用的是类自身的toString来转化。
到此为止,就完成了我们在接口中定义的那个方法的全部解析。
总结 【Android笔记|Retrofit2.5是如何解析在接口类中定义的方法()】Retrofit使用了动态代理,所以每次执行我们在接口中定义的方法会来到动态代理中的invoke方法,在这里面,又执行了loadServiceMethod来实现对方法的解析,主要是两个步骤:
  • 解析方法上面的注解(如@Headers,@POST,@GET)
  • 解析方法的请求参数前面的注解(如@Query, @Field)

    推荐阅读