阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680
本文将最后通过Retrofit2 源码解析来阐述网络访问框架设计。
<meta charset="utf-8">
Retrofit2 源码解析
注意: 本文是对源码的一个跟踪,会对每一行代码有具体的阐述,但是不会介绍 Retrofit 的设计模式。
Retrofit:一个 Restful 设计风格的 HTTP 网络请求框架的封装。基于 OkHttp
A type-safe HTTP client for Android and Java
0. 基本使用
1、Retrofit 将我们的 HTTP API 转换成一个 接口形式。所以我们第一步定义一个 interface
2、然后构建一个 Retrofit,通过 create 方法生成 GitHubService 的一个实现。
3、调用 listRepos 拿到 Call 实例,可以做同步或异步请求。
每个 Call 实例只能使用一次,但调用 clone() 将创建一个可以使用的新实例。
1. Retrofit 构建
1.1 Retrofit
首先看看 Retrofit 吧,这个类里面有7个实例变量。我们根据类型和变量名先猜猜是干什么用的,留个大体印象即可。
再来看看 Retrofit 的构造函数
并没做什么特殊的处理,就是简单的赋值,那想必所有初始化的操作都在 Builder 里了。
那么成功建立一个 Retrofit 对象的标准就是:配置好Retrofit 里的成员变量。
- callFactory : 网络请求 工厂
- baseUrl :网络请求的基本 Url 地址
- converterFactories :数据转换器 工厂集合
- callAdapterFactories :网络请求适配器 工厂集合
- callbackExecutor :回调方法执行器
1.2 Retrofit.Builder
我们可以看到 Builder 与 Retrofit 的参数几乎一样,只是少了 serviceMethodCache,多了个 Platform。这个 Platform 很重要。我们通过 Builder 的构造函数可以知道,调用了 Platform.get()方法,然后赋值给自己的 platform 变量。 我们看看这个 Platform 类。
get 方法会去调用 findPlatform 方法,这个里面很明显跟平台相关,Class.forName 要求 JVM 根据 className 查找并加载指定的类,如果未找到则抛出 ClassNotFoundException 。这里很明显我们分析 Android 平台,所以会 return 一个 Android()对象。
我们在这里面可以看到两个重要的方法
- defaultCallbackExecutor :这个方法返回的是个 Executor ,我们想到 Retrofit 正好有个 Executor 类型的变量,那么想必就是它了,它是 MainThreadExecutor 类型的,内部采用 handler 执行任务。
- defaultCallAdapterFactory :这个方法返回的是个 CallAdapter.Factory,Retrofit 成员变量中也正好有个 CallAdapter.Factory 类型的变量,所以说这个 Platform 很重要嘛,跟我们 Retrofit 类中的两个成员变量都有重大的关系。这里最终返回的是个 ExecutorCallAdapterFactory ,话说我们一开始就不知道这个 CallAdapter 是什么,更不用说这个 Factory 了,那我们先看看这个 ExecutorCallAdapterFactory 吧。
这里我们可以看到,把我们传进来的 Executor 保存起来了,这个 Executor 想必就是 MainThreadExecutor 了。至于 get 方法,我们暂时还不知道哪里用到了,所以后面的暂时不看了,到了这里还是不知道 CallAdapter.Factory 干嘛用的。
看来 Builder 方法很复杂呀,写了这么多只是讲了个 Platform,不过幸好这里面也包括了 Executor 和 CallAdapter.Factory ,那么现在我们正式看看 Builder.build()方法。
到这里,我们的 Retrofit 就构建完成了。如果按照我们 基本使用 中的例子,那么此刻,Retrofit 成员变量的值如下:
- serviceMethodCache :暂时为空的 HashMap 集合
- callFactory : OkHttpClient 对象
- baseUrl : 根据配置的baseUrl " https://api.github.com/ " 字符串, 构建出了一个 HttpUrl 对象
- converterFactories :一个 ArrayList 对象,里面存放着一个BuiltInConverters 对象
- callAdapterFactories :一个 ArrayList 对象,里面存放着一个 ExecutorCallAdapterFactory 对象
- callbackExecutor :MainThreadExecutor 对象
- validateEagerly :默认值 false
2. 创建网络请求接口实例,即 GitHubService service = retrofit.create(GitHubService.class);
接下来我们看看是怎样获得 GitHubService 实例的。
同样上源码,注意这里的 create 是非常重要的一个方法,这里使用了 外观模式 和 代理模式。
这里我们看到了 validateEagerly 变量,让我们看看它到底控制了什么。进 eagerlyValidateMethods 方法。
这里又见到了 Platform ,在 Retrofit.Builder 我们知道它返回的是 Android() 对象。 接着是个 循环 ,循环取出接口中的 Method ,接着调用 loadServiceMethod 。 loadServiceMethod 里面会根据 Method 生成一个 ServiceMethod,然后存入 serviceMethodCache , 那么我们大概知道,这是属于提前验证,会提前把接口中每个方法进行解析得到一个 ServiceMethod 对象,然后存入缓存中。 在 loadServiceMethod 中会取缓存中的值,如果有就直接返回 ServiceMethod。
由此可以知道 validateEagerly 变量是用于 判断是否需要提前验证解析的。
create 方法中 继续往下走,会看到 return 一个 代理对象 Proxy ,并转成了 T 类型,即 GitHubService 。
此时我们这句代码 GitHubService service = retrofit.create(GitHubService.class);
中的 service 有值了,它指向一个 实现了 GitHubService 接口的 代理对象 Proxy 。
3. 拿到 Call 对象 , 即 Call<List<Repo>> repos = service.listRepos("octocat");
这里我们的 service 是个代理对象,所以执行 listRepos 方法时, 会先走 InvocationHandler 中的 invoke 方法。
3.1 ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method);
首先 ServiceMethod 我们之前猜测过,应该是对 Method 的一个封装, 而这个 loadServiceMethod ,如果你还记得的话,我们在 create 的时候就碰到过,eagerlyValidateMethods 这个方法内部调用过 loadServiceMethod ,是为了加载这个 ServiceMethod 。现在我们来深入分析这个 loadServiceMethod 方法。
到这里其实 loadServiceMethod 已经分析完了,很简单,就是个 DCL 单例模式,然后获得 ServiceMethod 。
那其实我们现在的分析任务就很明确了,弄清楚这个 ServiceMethod 究竟是什么 。
3.1.1 ServiceMethod 分析
首先看看 ServiceMethod 的构造方法。 也是通过建造者模式构建的。其中很多变量其实都很熟悉了,比如 callFactory 、 baseUrl 。 对于 callAdapter、responseConverter 我们别弄混了,我们在 Retrofit 类中的变量是 callAdapterFactories 和 converterFactories , 是它们的工厂,是生产它们的地方。
接下来看 Builder 吧,毕竟这是真正做事的。
3.1.1.1 createCallAdapter ()
到这里,我们别忘了我们是在干嘛,我们是在获取 CallAdapter<T, R>
,好了,继续看 ExecutorCallAdapterFactory 的 get 方法。 解释都在代码注释里哟,一定要看看才知道现在到底是在干啥。话说源码分析,还是得靠自己认认真真读一次源码才行。
到这里,其实我们大概知道这个 CallAdapter 有什么用了,就是提供两个东西
- 网络请求响应要返回的类型 responseType
- retrofit2.Call< T > ,注意这里不是 okhttp3 下的 Call ,这里暂不深究。
因为我们不要忘了现在在做什么,我们现在是在获取 ServiceMethod 中的 callAdapter 变量值。所以看到这里返回了一个 CallAdapter 对象即可。
3.1.1.2 createResponseConverter ()
这里个方法是获取 响应转换器, 就是把网络请求得到的响应数据转换成相应的格式。
这里想必大家也知道套路了,跟获取 CallAdapter 是一样的,代码就不贴了,代码里同样是循环遍历 Retrofit 里的 converterFactories 变量。而这个 converterFactories 在我们的例子中是没有设置转换器的,所以它也只有一个默认的元素,即 BuiltInConverters 。 那么我们直接查看 它的 responseBodyConverter 方法。
通过这里我们可以知道,其实它会返回 null 。 所以我们 ServiceMethod 中的 Builder 中的 responseConverter 变量就等于 null 。
3.1.1.3 parseMethodAnnotation ()
我们来看看 解析方法注解 ,注意我们例子中这个方法里传的参数是 @GET 注解
至此,我们的 Builder 把 Http 的方法以及它的 Url 给分析完了,现在只剩 参数解析了。参数解析在 ServiceMethod 的 build 方法里已经讲过了 ,记得看注释。
呼~ 终于讲完了 ServiceMethod 的构造。这么大篇幅,由此可以看出 ServiceMethod 这个类非常重要。现在来总结一下,我们究竟拥有了些什么。
- callFactory : ExecutorCallAdapterFactory 实例
- callAdapter : ExecutorCallAdapterFactory中的get 方法返回的 CallAdapter 实例
- baseUrl : HttpUrl 实例
- responseConverter : 由于我们没设置,所以为 null
- httpMethod : 字符串 GET
- relativeUrl :字符串 users/{user}/repos
- headers : 没有设置 Headers ,所以为 null
- contentType : null
- hasBody : false
- isFormEncoded : false
- isMultipart : false
- parameterHandlers : 就我们例子而已,该数组有一个元素,Path 对象,它是 ParameterHandler 抽象类里的一个静态内部类。
由此可以看出,ServiceMethod 对象包含了访问网络的所有基本信息。
好吧,接下来还是得继续前行,别忘了,我们构建 ServiceMethod 只是在 invoke 方法内,并且这还只是第一步。接下来看第二步。
3.2 OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
这里是 new 一个 OkHttpCall 对象,这个 OkHttpCall 是 Retrofit 的 Call,它里面就是做请求的地方,会有 request、enqueue 等同步、异步请求方法,但是在这里面真正执行请求的是 okhttp3.Call ,即把请求委托给 okHttp 去执行。下面简要看看它的构造方法和一些成员变量吧,因为这里只是 new 操作,所以暂时不分析其余方法,用到的时候再看。
这样就把 OkHttpCall 给构建好了,接下来看第三步。
3.3 return serviceMethod.adapt(okHttpCall);
直接上代码
这是 前面构建好的 ServiceMethod 中的 adapt 方法,会去调用 callAdapter 的 adapt 方法,我们知道 ServiceMethod 中的 callAdapter 是 ExecutorCallAdapterFactory中的get 方法返回的 CallAdapter 实例。而这个实例的 adapt 方法会返回一个 ExecutorCallbackCall 对象。
到这里为止,我们已经成功的返回了一个 Call<List<Integer>>
4. 调用 Call 的 enqueue
趁热打铁,我们执行异步请求,看看怎样切换线程的。
可以看到是 delegate 执行了 enqueue 操作,而 delegate 就是我们的 OkHttpCall ,在 OkHttpCall 里的 enqueue 方法是这样工作的。
通过 okhttp3.Call call = serviceMethod.toCall(args);
构建一个真正执行请求的 Call ,即把请求交给 okhttp 去完成。而构建一个 Call 利用到了 ServiceMethod 中的 ParameterHandler 对象,这个对象是用来处理参数的。 它会把具体参数的值与 RequestBuilder 绑定起来。当然也用到了 ServiceMethod 自己,ServiceMethod 类似请求响应的大管家。
别忘了拿到响应后,在 okhttp3.Callback 中会去调用 response = parseResponse(rawResponse);
将响应转换成自己想要的格式,即定义的 Converter 。
原文链接:https://www.jianshu.com/p/abd144912e2a
阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/47438068