参考:
- 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, 还有许多的细节, 例如注解参数的校验, 拼接等等, 相信十分的繁琐, 不过我就先只写到这里了.