在流程梳理篇,我们介绍了ServiceMethod是其retrofit的核心部分,这篇我们就着重分析retrofit的ServiceMethod这个处理类
build建造者部分
对于ServiceMethod这部分的build,其构造如下:
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
这里传入了retrofit本身和目标的方法method
从method的getAnnotations/getGenericParameterTypes/getParameterAnnotations
这些方法中,可以看出retrofit这部分就是想方设法从method上获取到所有的信息
从上面的构造入手,一下子就想到在使用的时候我们的一些做法,举例:
@FormUrlEncoded
@POST("openapi.do")
public abstract Call<TranslateBean> hello(@Field("keyfrom") String keyfrom,
@Field("key") String key);
众所周知,一个request的组成基本上参数部分都是key-vale形式组成,那就不难理解为什么retrofit要求我们从通过方法注解/参数注解这些方式传入对应的关系了
理解了参数部分,我们看看build建造者最关键的方法build方法:
build方法较多,我们先折叠起来,看前半部分:
public ServiceMethod build() {
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
responseConverter = createResponseConverter();
...省略部分代码
return new ServiceMethod<>(this);
}
build方法上首先创建了一个callAdapter,提起callAdapter不免立马想到我们使用时传入的RxJavaCallAdapterFactory部分,我们顺着createCallAdapter看看跟我们RxJavaCallAdapterFactory有没有关系,
private CallAdapter<T, R> createCallAdapter() {
/**
* 首先通过method获取返回值类型,紧跟着对返回值类型合法性验证
*/
Type returnType = method.getGenericReturnType();
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.");
}
/**
* 接着获取方法上的注解,根据返回值类型和方法上的注解,调用retrofit的callAdapter
*/
Annotation[] annotations = method.getAnnotations();
try {
//noinspection unchecked
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);
}
}
而对于retrofit的callAdapter方法其上注解是这样描述的:
/**
* Returns the {@link CallAdapter} for {@code returnType} from the available {@linkplain
* #callAdapterFactories() factories}.
*
* @throws IllegalArgumentException if no call adapter available for {@code type}.
*/
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
即返回这种返回值类型的callDApter从callAdapterFactories中,那就很显然了,那就跟我们预想的一样,RxJavaCallAdapterFactory中返回目标返回值类型的callAdapter
对于callAdapter这部分是retrofit的高明之处,通过这个callAdapter大大增加了其语言的扩展性
CallAdapter部分
在callAdapter这里呢,只有两个方法,一个是
Type responseType();
,另一个是T adapt(Call<R> call);
这个方法是返回在请求响应时我们接收的bean的值类型对象 Type responseType(); 而最后这个方法是返回一个okhttp执行请求的call代理对象 T adapt(Call<R> call);
顺着上面的思路继续,在build方法中,紧跟着从callAdapter的responseType中获取返回值类型,根据这个返回值类型,调用createResponseConverter这个方法:
private Converter<ResponseBody, T> createResponseConverter() {
Annotation[] annotations = method.getAnnotations();
try {
return retrofit.responseBodyConverter(responseType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create converter for %s", responseType);
}
}
这个方法就与callAdapter很相似了,也是通过获取method方法上的参数,根据返回值类型和注解,调用retrofit的responseBodyConverter
对于responseBodyConverter这部分处理与callAdapter极其的相似
ResponseBodyConverter部分
一提到相似,我们也就能反应过来,我们传入的GsonConverterFactory,也是根据我们的要求返回我们所要的ResponseBodyConverter
/** * Returns a {@link Converter} for {@link ResponseBody} to {@code type} from the available * {@linkplain #converterFactories() factories} except {@code skipPast}. * * @throws IllegalArgumentException if no converter available for {@code type}. */ public <T> Converter<ResponseBody, T> nextResponseBodyConverter(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++) { /** * 通过converterFactory找到我们要的converter来进行转换 */ Converter<ResponseBody, ?> converter = converterFactories.get(i).responseBodyConverter(type, annotations, this); if (converter != null) { //noinspection unchecked return (Converter<ResponseBody, T>) converter; } } ...省略部分代码... }
既然通过createCallAdater和createResponseConverter这两个方法,把耦合的入口和出口都处理好了,下面就是进入参数处理的阶段了:
/**
* 通过method的注解遍历,对method的注解进行处理
*/
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
...省略部分代码...
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);
}
...省略部分代码...
剩余的方法主要就是parseMethodAnnotation和parseParameter这两个方法了
parseMethodAnnotation
这里只剪辑parseMethodAnnotation不过殊途同归,最终处理都是在parseHttpMethodAndPath中,对于parseHttpMethodAndPath
parseHttpMethodAndPath
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) { ...省略部分代码... 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); ...省略部分代码... } this.relativeUrl = value; this.relativeUrlParamNames = parsePathParameters(value); } 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); /** * 完成对url的处理 */ 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; } 最终我们得到目标方法的请求路径
由于parseParameterAnnotation情况分类比较多,这里仅拿field来进行讲解说明
...省略部分代码... /** * 首先获取字段名称 */ Field field = (Field) annotation; String name = field.value(); boolean encoded = field.encoded(); gotField = true; /** * 首先获取值类型 */ Class<?> rawParameterType = Utils.getRawType(type); /** * 如果值类型是Iterable的子类 */ if (Iterable.class.isAssignableFrom(rawParameterType)) { if (!(type instanceof ParameterizedType)) { throw parameterError(p, rawParameterType.getSimpleName() + " must include generic type (e.g., " + rawParameterType.getSimpleName() + "<String>)"); } ParameterizedType parameterizedType = (ParameterizedType) type; /** * 如果值类型是Iterable的子类,通过getParameterUpperBound获取实际类型的类型 */ Type iterableType = Utils.getParameterUpperBound(0, parameterizedType); /** * 通过type和注解找到转换的converter */ Converter<?, String> converter = retrofit.stringConverter(iterableType, annotations); /** * 将转换器/字段名称和字段是否encode处理存放在ParameterHandler的Field中 */ return new ParameterHandler.Field<>(name, converter, encoded).iterable(); } else if (rawParameterType.isArray()) { Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType()); Converter<?, String> converter = retrofit.stringConverter(arrayComponentType, annotations); return new ParameterHandler.Field<>(name, converter, encoded).array(); } else { Converter<?, String> converter = retrofit.stringConverter(type, annotations); return new ParameterHandler.Field<>(name, converter, encoded); }
将所有paramterHandler存放在builder的parameterHandlers中
ParameterHandler
ParameterHandlerd的实现不同实现有很多,有Body/RawPart/FieldMap/Field等等,这里用Field举例:
static final class Field<T> extends ParameterHandler<T> { private final String name; private final Converter<T, String> valueConverter; private final boolean encoded; Field(String name, Converter<T, String> valueConverter, boolean encoded) { this.name = checkNotNull(name, "name == null"); this.valueConverter = valueConverter; this.encoded = encoded; } @Override void apply(RequestBuilder builder, T value) throws IOException { if (value == null) return; // Skip null values. builder.addFormField(name, valueConverter.convert(value), encoded); } } 所有实现最关键的apply方法,向RequestBuilder中addFormField操作 构建请求数据
到这里Builder相关的方法就结束了
toRequest
toRequest方法是ServiceMethod其中的一个方法,从上面我们片面的了解parameterHandler帮我们构建form请求数据,这个方法就是ServiceMethod帮助我们统一进行对Request的创建
Request toRequest(Object... args) throws IOException {
/**
* 根据目标方法/baseUrl等创建RequestBuilder
*/
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
contentType, hasBody, isFormEncoded, isMultipart);
@SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
int argumentCount = args != null ? args.length : 0;
if (argumentCount != handlers.length) {
throw new IllegalArgumentException("Argument count (" + argumentCount
+ ") doesn't match expected count (" + handlers.length + ")");
}
/**
* 将之前构建的所有paramterhandler进行request处理
*/
for (int p = 0; p < argumentCount; p++) {
handlers[p].apply(requestBuilder, args[p]);
}
return requestBuilder.build();
}
至此retrofit部分的request处理就到这结束了,由于reqeustBuilder内容相对清晰,容易分析,这里就不加大篇幅来阐述这里的内容