前言
上一篇文章分析了 Retrofit2 的构建,接下来我们就来看下它的动态代理,看下它的 create()
方法中都做了什么。
如果想去了解一下 Retrofit2 的构建,可以看这篇文章。
Android Retrofit2 源码分析(一)—— Retroift 的构建
走进源码
create() 方法
public T create(final Class 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 {
......
//最重要的三个方法,我们从这里分析
//这里 ServiceMethod 的作用是解析返回参数,请求参数、类型等
ServiceMethod
这里有三个重要的方法,整个 create()
方法的核心就在这里,我们接下来重点分析这三个方法。
ServiceMethod
首先为了方便理解,先看下 ServiceMethod
这个类的注释说明
Adapts an invocation of an interface method into an HTTP call
可以看出这个类的作用是将接口方法调整为相关的 HTTP call。
我们直接看下上面调用的 loadServiceMethod()
方法
loadServiceMethod()
ServiceMethod loadServiceMethod(Method method) {
//在这里可以看到,关于 ServiceMethod,Retrofit 是做了相关缓存的,
//如果已经解析过这个接口的方法,那么直接从缓存取出
ServiceMethod result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
//生成相关 ServiceMethod 的放在这里
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
我们接下来看下 result = new ServiceMethod.Builder<>(this, method).build()
这行代码里面的具体实现。
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
Builder() 里面就是做一个字段的赋值,根据传入的参数获取到自己想要的数据。
我们再来看下 build。
public ServiceMethod build() {
//创建 Call 的适配器
callAdapter = createCallAdapter();
//还记得上一篇文章,默认的适配器中我们重点讲了 responseType(),
//这里就是调用 CallAdapter 方法来获取响应类型的。
responseType = callAdapter.responseType();
......
//创建数据转换器
responseConverter = createResponseConverter();
//解析方法中的所有注解,最后保存到 relativeUrlParamNames 中
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];
......
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
......
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
......
// 返回一个Service实例
return new ServiceMethod<>(this);
}
这里的判断太多了,我把一些判断的逻辑去掉,只看核心的方法。
还记得上篇文字中, retrofit 构建时关于 Adapter, Converter 的 list 吗, 在这里,ServiceMethod 将根据方法返回的类型等条件,选择相适应的 Adapter 和 Converter。
我们按着上面的逻辑一步步的去看下它们的具体实现。
createCallAdapter()
private CallAdapter createCallAdapter() {
//获取请求返回的类型
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.");
}
//获取方法注解
Annotation[] annotations = method.getAnnotations();
try {
//noinspection unchecked
//在这里调用了 retrofit 的 callAdapter
return (CallAdapter) 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);
}
}
上面调用了
public CallAdapter callAdapter(Type returnType, Annotation[] annotations) {
// 发现这里调用了 nextCallAdapter 方法
return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
//检查返回类型是不是 null
checkNotNull(returnType, "returnType == null");
//检查方法是否被注解
checkNotNull(annotations, "annotations == null");
//这里从0开始遍历
int start = callAdapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
//这个 get 具体的操作是由 CallAdapter 重写的,我们只需要知道这里获取了相匹配的 CallAdapter
CallAdapter adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
//如果不为 null, 那么就返回这个适配器
if (adapter != null) {
return adapter;
}
}
//这里是抛出相关异常的操作,我手动省略
......
}
这里就是创建 CallAdapter 的大致逻辑,根据接口方法返回的类型,方法的注解等相关信息,从我们构建 Retrofit 时生成的 CallAdapterList 中获取相关的适配器。
接下来我们看下 Retrofit 是怎么处理 Converter 的
createResponseConverter()
private Converter createResponseConverter() {
Annotation[] annotations = method.getAnnotations();
try {
//这里调用了 responseBodyConverter 方法,我们下面看一下
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);
}
}
这里逻辑很简单,获取注解数组,调用 retrofit 的 responseBodyConverter 方法。
那我们接着看
public Converter responseBodyConverter(Type type, Annotation[] annotations) {
//类似与 CallAdapter 的创建,这里也是这样一个差不多的方法
return nextResponseBodyConverter(null, type, annotations);
}
public Converter 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 的 responseBodyConverter 获取对应的 Converter
Converter converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
if (converter != null) {
//noinspection unchecked
return (Converter) converter;
}
}
}
这里的方法和 CallAadpter 的创建实在是太像了,我也不详细说了。
我们再跟着 ServiceMethod 的 build 方法中继续看下去
parseMethodAnnotation()
到这里 Retrofit 将开始解析我们使用的注解了,话不多说,走进源码看一下。
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;
}
}
这里就涉及到了相关方法的注解,种类可以说是非常全面了,看上面的代码可以发现,最终都是根据注解类型传入不同的参数到 parseHttpMethodAndPath()
方法中
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);
}
//这里就是 Http 的请求类型
this.httpMethod = httpMethod;
//是否有请求体
this.hasBody = hasBody;
//检查请求路径是否为空
if (value.isEmpty()) {
return;
}
//下面这段我主要是看注释去理解的,主要是获取查询路径和请求字符串,
//同时要确保请求参数要有替代的字符串,如果是动态的请求参数,应该使用 @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);
}
}
this.relativeUrl = value;
//解析路径参数,返回一个 Set,内部存放了这个请求对应的请求字段
this.relativeUrlParamNames = parsePathParameters(value);
}
这里其实就是解析我们接口类中所有的方法注解,根据注解不同 Retrofit 将为我们解析出不同的请求方式,最后存储到 relativeUrl
和 relativeUrlParamNames
中,到最后都会存储到 serviceMethodCache
这个缓存里。
ServiceMethod 总结
这里我们重点分析了 CallAdapter、ReponseConverter、方法注解的解析。后面还有一步参数注解的解析,就不走下去了,代码实在太长。
可以知道 ServiceMethod 的作用,就是根据方法返回类型等不同,生成 CallAdapter 和 Converter,同时还会根据方法注解,参数注解,生成相应的信息,存到缓存中。
简单来说,ServiceMethod 的作用就是将我们的接口请求方法解析成可以给 Call 使用的数据,以便于之后生成 Call。
OkHttpCall
create()
方法最重要的三步 loadServiceMethod
, 关于 OkHttpCall 其实就是根据 ServiceMethod 来生成的,在后面我们请求接口的时候,将会返回一个 CallbackCall
给我们使用。
这里我们就看下 Retrofit 中是怎么对 OkHttp 的 call 做包装的。
OkHttpCall 的 enqueue() 方法
@Override public void enqueue(final Callback callback) {
checkNotNull(callback, "callback == null");
okhttp3.Call call;
Throwable failure;
//生成 RawCall,
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
call = rawCall;
failure = creationFailure;
if (call == null && failure == null) {
try {
//其实这里就是调用 ServiceMethod 中的 toCall 方法生成一个 Call
call = rawCall = createRawCall();
} catch (Throwable t) {
throwIfFatal(t);
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
//这里调用了 OkHttp 包中的 enqueue 方法做请求
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
}
这里我们粗略的看一下,其实就是生成一个 OkHttp 包中我们熟悉的 call,我们接下来继续看方法调用时返回的 serviceMethod.adapt(okHttpCall)
。
serviceMethod.adapt(okHttpCall)
T adapt(Call call) {
return callAdapter.adapt(call);
}
这里调用了 CallAdapter 的 adapt 方法,我们去看上一章提到的 Android 使用时默认的 ExecutorCallAdapterFactory
中的 adapt()
方法
@Override public Call adapt(Call call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
这里我们看下一下它给我们返回的 ExecutorCallbackCall
ExecutorCallbackCall(Executor callbackExecutor, Call delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
//因为我们请求的时候调用是这个方法,所以重点看下这个
@Override public void enqueue(final Callback callback) {
checkNotNull(callback, "callback == null");
// 其实就是调用了 call 的 enqueue,在这里根据请求的结果给我们不同的回调
delegate.enqueue(new Callback() {
@Override public void onResponse(Call call, final Response response) {
callbackExecutor.execute(new Runnable(
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}
@Override public void onFailure(Call call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
这里的相对来说流程就十分简单,大致的看一下注释就行了。
总结
一波分析过来,关于 Retrofit2 create()
方法也分析完了,大致看过来,可以发现核心其实就是 ServiceMethod 这个类,它不仅解析方法注解,参数注解,还会根据当前方法的返回类型适配相应的适配器,当然 Converter 也在这里使用。
我们使用接口的时候,大致流程就是 Retrofit2 使用动态代理生成了一个相应的 Call, 同时它会将这个 Call 封装成一个 CallBackCall 来提供给我们使用。
Retrofit2 的源码分析就到这里了,大致的看下来,也可以知道它是如何优雅的封装了 OkHttp 的吧!