retrofit 是基于okhttp,使用动态代理来实现的。
动态代理
动态代理在retrofit中其实就是在运行期间去创建interface实例的。我们在使用时都会创建一个interface类,里面再添加一些接口方法。
public <T> T create(final Class<T> service) {
return (T)
Proxy.newProxyInstance(
service.getClassLoader(),
new Class<?>[] {service},
new InvocationHandler() {
.....
}
}
在create方法中就实现了动态代理,通过这种防暑组建okhttp的request 和 Call 进行请求。
解析构建请求
动态代理的主要操作是在InvocationHandler#invoke
中,
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
args = args != null ? args : emptyArgs;
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
按照正常的流程的话,方法会走到loadServiceMethod
里面这里才是真正处理的地方。
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;
}
这里主要是为了获取ServiceMethod对象,通过代理方式获取之后缓存起来下次直接取。
如果本次没获取到将会解析注解和方法。
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
method,
"Method return type must not include a type variable or wildcard: %s",
returnType);
}
if (returnType == void.class) {
throw methodError(method, "Service methods cannot return void.");
}
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
RequestFactory.parseAnnotations
这一步就是处理注解,构建RequestFactory对象,其实和在Okhttp中构建Request基本相同。
HttpServiceMethod.parseAnnotations
这步操作主要就是构建CallAdapter 和 数据转换的 Converter
在使用rxjava2的时候我们一般构建retrofit时会使用Rxjava2CallAdapterFactory
这是接口方法的返回值会是Observable
类型。如果不加任何calladapter的话,默认的返回类型就是Call。但是如果使用Kotlin 协程+ suspend 就可以直接写返回值类型,无需泛型表示。这是因为新版的Retrofit对suspend方法进行了处理。
if (!isKotlinSuspendFunction) {
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
} else if (continuationWantsResponse) {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>)
new SuspendForResponse<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
} else {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>)
new SuspendForBody<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
continuationBodyNullable);
}
如果时使用了suspend 并且返回参数直接写的时想要的结果,而不是Call 的话就会返回 SuspendForBody
这个和返回其他的差别还要从最初的invoke方法来看。
loadServiceMethod(method).invoke(args) ---->
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
然后执行adapt方法。
这个抽象方法有三个实现,分别在
CallAdapted
SuspendForResponse
SuspendForBody
在SuspendForBody中的adapt方法中
有一个KotlinExtensions.await(call, continuation)
override fun onResponse(call: Call<T>, response: Response<T>) {
if (response.isSuccessful) {
val body = response.body()
if (body == null) {
val invocation = call.request().tag(Invocation::class.java)!!
val method = invocation.method()
val e = KotlinNullPointerException("Response from " +
method.declaringClass.name +
'.' +
method.name +
" was null but response body type was declared as non-null")
continuation.resumeWithException(e)
} else {
continuation.resume(body)
}
} else {
continuation.resumeWithException(HttpException(response))
}
}
这里会直接解析除body然后根据GsonCovertFactory进行数据转换转化成实体类。
以上纯属个人分析,如有错误,还望指正