文章目录
- create()
- `validateServiceInterface()`
- 动态代理
- `loadServiceMethod(method)`
create()
让我们先深入到create 里,
public <T> T create(final Class<T> service) {validateServiceInterface(service);....
}
validateServiceInterface()
我们发现首先会执行validateServiceInterface()
,名字意思为验证服务接口,传入的参数也是接口所对应的类文件。
private void validateServiceInterface(Class<?> service) {// 1. 检查传入的参数是否为接口if (!service.isInterface()) {throw new IllegalArgumentException("API declarations must be interfaces.");}// 2. 使用双端队列来存储待检查的接口Deque<Class<?>> check = new ArrayDeque<>(1);check.add(service);while (!check.isEmpty()) {// 从队列中取出接口Class<?> candidate = check.removeFirst();// 检查接口是否有泛型参数if (candidate.getTypeParameters().length != 0) {StringBuilder message =new StringBuilder("Type parameters are unsupported on ").append(candidate.getName());if (candidate != service) {message.append(" which is an interface of ").append(service.getName());}// 如果接口包含泛型参数,则抛出异常throw new IllegalArgumentException(message.toString());}// 将接口的父接口添加到检查队列中Collections.addAll(check, candidate.getInterfaces());}// 3. 如果设置了validateEagerly标志为true,则进行进一步的验证if (validateEagerly) {Platform platform = Platform.get();// 遍历接口中声明的方法for (Method method : service.getDeclaredMethods()) {// 检查方法是否为默认方法且不是静态方法if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {// 加载服务方法loadServiceMethod(method);}}}}
我们可以分三部分看看他是如何验证接口的:
- 第一部分简单判断这个类引用是否为接口(
!service.isInterface()
),否则抛出异常. - 第二部分,这里是先创建了一个双向队列(ArrayDeque),然后并将这个service添加到队列中。然后进入一个循环,直到队列为空。在每次循环中,从队列的开头取出一个service用于检查。如果发现有一个元素含泛型(
candidate.getTypeParameters().length != 0
),则抛出异常.提示"Type parameters are unsupported on …",其中包含相应类的名称。如果取出来的service不是初始的service类,错误消息还会指示它是service的接口之一。最后,将candidate
的所有接口添加到队列中,以便进一步检查它们是否有类型参数。 - 第三部分我们看到了一个
validateEagerly
的标志位(激进验证),如果标志位validateEagerly
为真,即需要进行全面验证,则获取当前平台(Platform
)的实例。然后,遍历service类声明的所有方法。对于不是默认方法(default method)且不是静态方法的每个方法(Retrofit不支持或不认为是),调用loadServiceMethod
方法进行加载,遍历方法进行加载,就算验证的一部分了。 - 在我们使用Retrofit时,我们建立的xxxService接口里的方法在第一次加载时会进行初始化操作,在
create()
中,就会进行,这样更早的快速暴露问题,但是在初始化的过程中也会进行一些反射的内容,很耗时。
动态代理
接下来让我们看create()剩下部分的实现
public <T> T create(final Class<T> service) {// 验证服务接口的有效性validateServiceInterface(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];@Overridepublic @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)throws Throwable {// 如果方法是 Object 类的方法,则执行普通的调用if (method.getDeclaringClass() == Object.class) {return method.invoke(this, args);}args = args != null ? args : emptyArgs;// 如果方法是默认方法(Java 8 及以上版本),则调用默认方法实现return platform.isDefaultMethod(method)? platform.invokeDefaultMethod(method, service, proxy, args): loadServiceMethod(method).invoke(args);}});}
可以看出来后面的内容只是一个方法的调用:newProxyInstance()
动态代理
有三个参数,
service.getClassLoader()
简单获取的类加载器new Class<?>[] { service }
动态代理的接口new InvocationHandler()
后边代理实例调用方法
所以我们只需要看真正的实现,真正干事的部分,即代理实例调用方法的部分的invoke()
里,在实际操作里,会执行对应Retrofit生成的动态代理类的invocationHandler.invoke()
@Overridepublic @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)throws Throwable {// 如果方法是 Object 类的方法,则直接 执行普通的调用,不会代理if (method.getDeclaringClass() == Object.class) {return method.invoke(this, args);}args = args != null ? args : emptyArgs;// 如果方法是默认方法(Java 8 及以上版本),则调用默认方法实现return platform.isDefaultMethod(method)? platform.invokeDefaultMethod(method, service, proxy, args): loadServiceMethod(method).invoke(args);}}
老版本Android不支持Java8,也不知道什么叫默认方法
@IgnoreJRERequirement // Only called on API 24+.boolean isDefaultMethod(Method method) {return hasJava8Types && method.isDefault();//会检测是否有java8 对应的特性,那我直接返回false}
那么核心代码从invoke()
走到了loadServiceMethod(method).invoke(args);
里边的args : args = args != null ? args : emptyArgs;
loadServiceMethod(method)
ServiceMethod<?> loadServiceMethod(Method method) {// 1首先尝试从缓存serviceMethodCache中获取已存在的 ServiceMethod 对象ServiceMethod<?> result = serviceMethodCache.get(method);if (result != null) return result;// 2如果缓存中不存在,则需要进行同步操作,确保线程安全synchronized (serviceMethodCache) {// 2再次尝试从缓存中获取 ServiceMethod 对象result = serviceMethodCache.get(method);if (result == null) {// 如果缓存中依然不存在,则需要解析注解并创建 ServiceMethod 对象result = ServiceMethod.parseAnnotations(this, method);// 将新创建的 ServiceMethod 对象添加到缓存中serviceMethodCache.put(method, result);}}return result;
}
整个过程就是一个带缓存(serviceMethodCache
)的加载,缓存中有直接返回,没有则先进行创建,再放到缓存中然后返回.
serviceMethodCache
是Retrofit2的一个缓存机制(实际上是Map),用于缓存已经解析的ServiceMethod
对象,ServiceMethod
对象代表了一个被注解修饰的接口方法,每一个接口方法都有对应。(毕竟解析注解很耗时)
所以此处的核心代码其实是如何创建对应的ServiceMethod
,也就是:
result = ServiceMethod.parseAnnotations(this, method);
我们继续深入跟进:
abstract class ServiceMethod<T> {static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {// 第1步:解析方法的注解,创建RequestFactory对象,RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);// 第2步:获取方法的返回类型Type returnType = method.getGenericReturnType();// 第3步:检查返回类型是否包含类型变量或通配符if (Utils.hasUnresolvableType(returnType)) {throw methodError(method,"方法的返回类型不能包含类型变量或通配符:%s",returnType);}// 第4步:检查返回类型是否为voidif (returnType == void.class) {throw methodError(method, "服务方法不能返回void。");}// 第5步:解析HTTP服务方法特定的注解return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);}//使用给定的参数调用服务方法,并返回结果。。。abstract @Nullable T invoke(Object[] args);
}
我们发现:
- 调用了
RequestFactory.parseAnnotations(retrofit, method);
,并保存返回值,这里是工厂模式 HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory)
;- 下边的
invoke()
很眼熟,这不正好是前边loadServiceMethod(method).invoke(args)
;的吗
核心代码是第1步和第5步,该方法的目的还是获取Service接口所对应的ServiceMethod<T>
最后返回的还是HttpServiceMethod
的方法。即HttpServiceMethod.parseAnnotations()
那么既然转换注解还是靠该类实现的,那么最最重要的最终的invoke()
是不是也是一个该类实例呢?
我们发现点进去后是:abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT>
这是一个继承ServiceMethod<T>
的类,很有趣,似乎熟悉的又回来了,那么继承了该类,HttpServiceMethod
就一定会实现invoke()
这个抽象方法:
@Overridefinal @Nullable ReturnT invoke(Object[] args) {Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);return adapt(call, args);//抽象方法}
这里是先生成了一个OkHttpCall()
,(毕竟Retrofit底层还是okhttp)并且作为参数带入了adapt()
方法
- 这⾏代码负责将
ServiceMethod
解读到的信息(主要是⼀个RequestFactory
、⼀个OkHttpClient
和⼀个ResponseConverter
)封装进OkHttpCall
; - ⽽这个对象可以在需要的时候(例如它的
enqueue()
⽅法被调⽤的时候), 利⽤RequestFactory
和OkHttpClient
来创建⼀个okhttp3.Call
对象,并调⽤这个对象来发起⽹络请求, - 然后利⽤
ResponseConverter
对结果进⾏预处理之后,交回给 Retrofit 的 Callback 。
在实际操作中,异步请求是实际上交给了okhttp来做,在OkHttpCall类中,这里有异步请求的底层,通过parseResponse(rawResponse)
转换成对象。
call.enqueue(new okhttp3.Callback() {@Overridepublic void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {Response<T> response;try {//将字节序列转换成对象response = parseResponse(rawResponse);} catch (Throwable e) {throwIfFatal(e);callFailure(e);return;}try {callback.onResponse(OkHttpCall.this, response);} catch (Throwable t) {throwIfFatal(t);t.printStackTrace(); // TODO this is not great}}
接着来看adapt()
,adapt()意思就是适配,转换。它是一个抽象方法,
那我们只能继续回看到parseAnnotations
这个方法:代码很长,我此处只显示真正的核心部分
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(///....省略n行if (!isKotlinSuspendFunction) {//核心部分,生成HttpServiceMethod并返回return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);} else ...
}
这里new了一个HttpServiceMethod
的内部类CallAdapter()
,最后还是会走到:
callAdapter.adapt(call);
这个⽅法会使⽤⼀个 CallAdapter 对象来把 OkHttpCall 对象进⾏转换,⽣成⼀个新的对象。
- 默认情况下,返回的是⼀个
ExecutorCallbackCall
,它的作⽤是把操作切回主线程后再交给 Callback 。
另外,如果有⾃定义的 CallAdapter,这⾥也可以⽣成别的类型的对象,例如 RxJava 的 Observable