前言
上一篇文章分析了 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 的吧!