参考:
- Idtk:Retrofit源码解析
 - 俞其荣: Retrofit 源码解析
 - Carson_Ho: Android:手把手带你 深入读懂 Retrofit 2.0 源码
 - Piasy: 拆轮子系列:拆 Retrofit
 - codeGoogle: 带你一起探究Retrofit 源码,让你不再畏惧Retrofit的面试提问
 
准备
和上次看okhttp的源码一样, 先把源码clone下来, 导入Intellij IDEA用maven构建
使用示例
1  | Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")  | 
同步请求
1  | new Thread(new Runnable() {  | 
异步请求
1  | GankApi gankApi = mRetrofit.create(GankApi.class);  | 
Retrofit的创建
从这句代码我们点进去看
1  | Retrofit retrofit = new Retrofit.Builder()  | 
1  | Builder(Platform platform) {  | 
看一下Platform.get()方法
1  | class Platform {  | 
从上面的代码可以看出通过Class.forName反射获取类名的方式,来判断当前的平台是Android或者是java8又或者是一个默认的平台.
我们Android这个类, 可能后面要用到
1  | static class Android extends Platform {  | 
Retrofit.create
看一下这个方法
1  | public <T> T create(final Class<T> service) {  | 
这个方法, 我们进去的是一个interface的字节码对象, 然后得到的是却是一个这个interface的对象, 代理类在程序运行前不存在、运行时由程序动态生成的代理方式称为动态代理。
关于动态代理, 我们还是写一个例子来理解比较好点
新建一个interface
1  | public interface Flyable {  | 
再建一个委托类(也就是被代理的类)叫做Bird, 模拟鸟在空中飞行的时间, 动态代理要求委托类必须实现了某个接口,比如这里委托类Bird实现了Flyable
1  | public class Bird implements Flyable {  | 
现在我想要统计Bird的飞行时间, 要怎么做呢?
新建一个类实现InvocationHandler接口
1  | public class TimingInvocationHandler implements InvocationHandler {  | 
这里的这个target表示委托类对象, 从外部传进来, 也就是上面的Bird对象InvocationHandler是负责连接代理类和委托类的中间类必须实现的接口。其中只有一个public Object invoke(Object proxy, Method method, Object[] args)
proxy表示通过Proxy.newProxyInstance()生成的代理类对象
method表示代理对象被调用的函数
args表示代理对象被调用的函数的参数
调用代理对象的每个函数实际最终都是调用了InvocationHandler的invoke函数。这里我们在invoke实现中添加了开始结束计时,其中还调用了委托类对象target(也就是传进来的bird对象)的相应函数,这样便完成了统计执行时间的需求.
接下来通过 Proxy 类静态函数生成代理对象
1  | public class Main {  | 
输出结果:
1  | fly  | 
我们可以这样理解,如上的动态代理实现实际是双层的静态代理,开发者提供了委托类 Bird(就是被代理的对象),程序动态生成了代理类Flyable。开发者还需要提供一个实现了InvocationHandler的子类TimingInvocationHandler,TimingInvocationHandler是代理类Flyable的委托类,委托类Bird的代理类。用户直接调用代理类Flyable的对象,Flyable将调用转发给委托类TimingInvocationHandler,TimingInvocationHandler再将调用转发给它的委托类Bird。
关于更多动态代理的知识, 可以看看这几篇
公共技术点之 Java 动态代理
10分钟看懂动态代理设计模式
从一道面试题开始说起 枚举、动态代理的原理
OK, 理解了动态代理之后, 我们可以看看Retrofit.create()这个方法了
1  | public <T> T create(final Class<T> service) {  | 
注释我已经在代码中写好了
重点就是这三句代码
1  | ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method);  | 
 我们来看看核心方法
先看这个
1  | ServiceMethod<?, ?> loadServiceMethod(Method method) {  | 
我们看看这个ServiceMethod是怎么构建出来的
1  | Builder(Retrofit retrofit, Method method) {  | 
这两个方法主要就是对API接口中的方法进行解析, 构造一个ServiceMethod, 然后返回给OkHttpCall使用.大致做了这些事情:
- 创建CallAdapter
 - 创建ResponseConerter
 - 根据API接口方法的注解构造网络请求方法
 - 根据API接口方法参数中的注解构造网络请求的参数
 - 检查有无异常
接下来看看OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);这个方法
OkHttpCall的构造方法是这样的, 没什么可说 
1  | OkHttpCall(ServiceMethod<T, ?> serviceMethod, Object[] args) {  | 
接着再看return serviceMethod.callAdapter.adapt(okHttpCall);这个方法
这个serviceMethod.callAdapter就是serviceMethod在构建的时候创建出来的callAdapter, 跟踪createCallAdapter()这个方法, 在 Retrofit 中默认的 callAdapterFactory 是 ExecutorCallAdapterFactory, 所以这个callAdapter是由一个ExecutorCallAdapterFactory(来自于retrofit的adapterFactories)的get(Type returnType, Annotation[] annotations, Retrofit retrofit)生成的
1  | final class ExecutorCallAdapterFactory extends CallAdapter.Factory {  | 
可以看到这个get()方法返回了一个匿名内部类, 它的adpter方式是return new ExecutorCallbackCall<>(callbackExecutor, call);
看一下这个构造方法
1  | static final class ExecutorCallbackCall<T> implements Call<T> {  | 
ExecutorCallbackCall实现了Retrofit.Call接口, 而我们看到OkHttpCall也是实现了Retrofit.Call接口的, 这个接口中的方法有execute(), enqueue(), isExecuted(), cancel(), isCanceled(), clone(), request()一共7个, 这里使用装饰者模式, 所以我们不妨将代码改写成这样更清楚一些
1  | public <T> T create(final Class<T> service) {  | 
serviceMethod中包含了从create()方法中传入的接口字节码文件的所有方法, url, CallFactory, ResponseConverter等, 然后又把这个serviceMethod传入了OkHttpCall构造了一个okhttpCall对象, 然后又把这个okhttpCall对象传入了ExecutorCallbackCall构造了一个ExecutorCallbackCall对象.根据上面动态代理的知识, retrofit.create()会返回一个接口的对象, 调用这个接口对象的方法会调用InvocationHandler中的invoke方法, 返回值也是invoke方法的返回值, 而invoke方法的返回值是一个ExecutorCallbackCall对象, 一般我们都使用Retrofit.Call类型的变量来引用retrofit.create()返回的对象(因为接口中的方法的返回类型是Call嘛), 而正好ExecutorCallbackCall是实现了Retrofit.Call的, 所以这里不会有问题.同时ExecutorCallbackCall使用了装饰者模式
1  | static final class ExecutorCallbackCall<T> implements Call<T> {  | 
从上面的代码可以看到很显然这是装饰者模式, 对OkHttpCall的方法进行了包装.在retrofit.create()得到一个Call对象之后, 调用这个Call对象的enqueue()方法实际上是调用一个ExecutorCallbackCall对象的enqueue()方法, 不信可以将这个Call对象的名字打印一下
而ExecutorCallbackCall对象的enqueue()方法其实又是调用了传入进去的Retrofit2.OkHttpCall对象的enqueue()方法
ExecutorCallbackCall.execute()
接下来我们看看ExecutorCallbackCall.execute()吧, 异步的一会儿再看.
1  | public Response<T> execute() throws IOException {  | 
刚才说了, 这里的delegate其实是Retrofit.create()方法里传进来的OkHttpCall对象, 所以我们去看看
1  | public Response<T> execute() throws IOException {  | 
注意一下注释中标记的createRawCall()方法, 我们跟踪一下
1  | private okhttp3.Call createRawCall() throws IOException {  | 
可以看到这里其实返回的是一个okhttp3.Call对象, 然后在execute()方法里调用parseResponse(call.execute())方法将结果返回, 我们去看看这个方法
1  | Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {  | 
必要的注释我已经写了, 再看一下serviceMethod.toResponse(catchingBody);方法
1  | /** Builds a method return value from an HTTP response body. */  | 
那个这个responseConverter是在哪里赋值的呢?赋进去的是一个什么呢?
其实是在retrofit对象创建的时候, 在Retrofit.Builder的构造方法里
1  | Builder(Platform platform) {  | 
可以看到加入了一个即使没有指定, 也加入了一个BuildInConverters, 里面包含了多种converter, 而serviceMethod里面的converter是在ServiceMethod的这里生成的
1  | public ServiceMethod build() {  | 
具体的细节我就不细究了, 有时间再研究.总之用的是BuildInConverters中的responseBodyConverter()方法得到的Converter.看一下代码
1  | final class BuiltInConverters extends Converter.Factory {  | 
异步请求
关于异步请求, 我不想说的太多, 只说一下如何将okhttp中子线程的请求结果回调到主线程, 就贴几张图吧
注意到这个callbackExecutor, 又是从这里传进来
在这里被调用
而其实这里的platform是Android
总结
Retrofit的源码用到了不少设计模式, 外观模式,动态代理,策略模式,观察者模式, 简单点的还有 Builder 模式,工厂等.
CallAdapterFactory决定了interface中请求方法的返回类型, 比如默认是Call类型, 如果是RxJavaCallAdapterFactory就能返回Observable类型, 而ConverterFactory决定了返回类型的泛型, 比如这么一个interface
1  | public interface GankApi {  | 
Call类型还是Observable类型由CallAdapterFactory决定.
默认的ConverterFactory只能返回ResponseBody类型, 而加了GsonConverterFactory之后就能返回POJO类型, 也就是MeizhiModel类型.
关于这几点, 推荐怪盗kidou的这篇你真的会用 Retrofit2 吗? Retrofit2 完全教程, 写的十分的详细
关于retrofit, 还有许多的细节, 例如注解参数的校验, 拼接等等, 相信十分的繁琐, 不过我就先只写到这里了.