前言
- 在Android开发中网络请求很常见,而在网络请求库中,retrofit因为他巧妙的封装和解耦思想,成为了Android最热门的网络请求框架。
- 准确来说,Retrofit 是一个 RESTful 的 HTTP 网络请求框架的封装。
- 网络请求的工作本质上是
OkHttp
完成,而 Retrofit 仅负责 网络请求接口的封装。Okhttp源码分析,请移步
基本使用
首先看看Retrofit的使用,对Retrofit有个直观的感受,便于下面的源码分析。
1、 定义http请求接口
1 | public interface GitHubService { |
2、构建retrofit的实例
1 | Retrofit retrofit = new Retrofit.Builder() |
3、创建http请求接口的实例
1 | GitHubService service = retrofit.create(GitHubService.class); |
4、调用接口实例的方法,生成Call对象,执行请求
1 | Call<List<Repo>> repos = service.listRepos("websocket"); |
源码分析
文章分析的源码版本是2.4.0
1、创建Retrofit实例
retrofit实例的创建使用了建造者模式,所以开发者并不需要关心配置细节就可以创建好Retrofit实例。在创建Retrofit对象时,你可以通过更多更灵活的方式去处理你的需求,如使用不同的Converter、使用不同的CallAdapter,这也就提供了你使用RxJava来调用Retrofit的可能。这部分源码比较简单,可以自行查看源码。
builder 模式,外观模式(门面模式),这就不多说了,可以看看 stay 的 Retrofit分析-经典设计模式案例这篇文章。
2、创建http请求接口的实例
1 | GitHubService service = retrofit.create(GitHubService.class); |
通过create()方法创建请求接口的实例,我们来看看create()方法是怎么实现的
1 | public <T> T create(final Class<T> service) { |
创建 请求接口的实例使用的是动态代理技术。
简而言之,就是动态生成接口的实现类(当然生成实现类有缓存机制),并创建其实例(称之为代理),代理把对接口的调用转发给 InvocationHandler
实例,而在 InvocationHandler
的实现中,除了执行真正的逻辑(例如再次转发给真正的实现类对象),我们还可以进行一些有用的操作,例如统计执行时间、进行初始化和清理、对接口调用进行检查等。
3、调用接口实例的方法
当我们调用接口实例的方法listRepos()时,会调用自身的InvocationHandler#invoke(),得到最终的Call对象,我们接着看invoke()方法:
1 | public Object invoke(Object proxy, Method method, @Nullable Object[] args) |
2.1、ServiceMethod
我们首先来分析第(1)代码
1 | ServiceMethod<Object, Object> serviceMethod = |
ServiceMethod
是个什么鬼??? 不着急,我们先看loadServiceMethod()
方法的实现:
1 | ServiceMethod<?, ?> loadServiceMethod(Method method) { |
看到这里可能你会有疑问,同步代码里为什么还要再取一次缓存?
因为可能两个线程的请求都走到了synchronized之前,一个线程继续往下走,解析注解配置获得了serviceMethod对象并放到了缓存中,这个时候其实缓存里已经有serviceMethod对象了,另外一个线程走进来不需要再去解析注解配置了,所有需要再获取一遍。
接着我们继续看ServiceMethod
的构造方法,看完你就知道他是个什么鬼了,哈哈
1 | ServiceMethod(Builder<R, T> builder) { |
可以看到ServiceMethod类主要是网络请求配置的封装,这个里面我们重点关注callFactory
,callAdapter
,responseConverter
,parameterHandlers
这四个对象
2.1.1 callFactory
通过上面的代码我们可以看到callFactory
主要是通过Retrofit
对象拿到的,而我们在构造 Retrofit
对象时,可以指定 callFactory
,如果不指定,将默认设置为一个 okhttp3.OkHttpClient
2.1.2 callAdapter
callAdapter
是在build方法里设置的,在build()
方法里调用了createCallAdapter()
方法:
1 | private CallAdapter<?> createCallAdapter() { |
可以看到,callAdapter
还是由 Retrofit
类提供。在 Retrofit
类内部,将遍历一个 CallAdapter.Factory
列表,让工厂们提供,如果最终没有工厂能(根据 returnType
和 annotations
)提供需要的 CallAdapter
,那将抛出异常。而这个工厂列表我们可以在构造 Retrofit
对象时进行添加。
2.1.3 responseConverter
1 | private Converter<ResponseBody, T> createResponseConverter() { |
同样,responseConverter
还是由 Retrofit
类提供,而在其内部,逻辑和创建 callAdapter
基本一致,通过遍历 Converter.Factory
列表,看看有没有工厂能够提供需要的 responseBodyConverter。工厂列表同样可以在构造 Retrofit
对象时进行添加。
2.1.4 parameterHandlers
每个参数都会有一个 ParameterHandler
,由 ServiceMethod#parseParameter
方法负责创建,其主要内容就是解析每个参数使用的注解类型(诸如 Path
,Query
,Field
等),对每种类型进行单独的处理。构造 HTTP 请求时,我们传递的参数都是字符串,那 Retrofit 是如何把我们传递的各种参数都转化为 String 的呢?还是由 Retrofit
类提供 converter!
Converter.Factory
除了提供上一小节提到的 responseBodyConverter,还提供 requestBodyConverter 和 stringConverter,API 方法中除了 @Body
和 @Part
类型的参数,都利用 stringConverter 进行转换,而 @Body
和 @Part
类型的参数则利用 requestBodyConverter 进行转换。
这三种 converter 都是通过“询问”工厂列表进行提供,而工厂列表我们可以在构造 Retrofit
对象时进行添加。
上面提到了三种工厂:okhttp3.Call.Factory
,CallAdapter.Factory
和 Converter.Factory
,分别负责提供不同的模块,至于怎么提供、提供何种模块,统统交给工厂,Retrofit 完全不掺和,它只负责提供用于决策的信息,例如参数/返回值类型、注解等。
除了上面重点分析的这四个成员,ServiceMethod
中还包含了 API 方法的 url 解析等逻辑,包含了众多关于泛型和反射相关的代码,例如parseMethodAnnotation()
方法,里面主要是解析http的请求方法和地址以及请求头。
2.2、OkHttpCall
接着我们来分析第(2)代码
1 | OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args); |
OkHttpCall
实现了 retrofit2.Call
,我们通常会使用它的 execute()
和 enqueue(Callback<T> callback)
接口。
我们看同步执行 execute()
方法:
1 | //OkHttpCall.java |
在toCall()
方法中,通过ServiceMethod
中的httpMethod
,baseUrl
,parameterHandlers
等等来创建RequestBuilder
对象,最后调用callFactory.newCall()
来创建okhttp3.Call对象。接着我们看返回值的解析:
1 | //OkHttpCall.java |
在 toResponse
函数中,就是调用我们设置的内容转换器或者是默认的内容转换器完成响应的数据转换。
看到这里,我们发现,在ServiceMethod
中的相关配置在OkHttpCall
中基本都用到了,但是我们发现callAdapter
还没使用到,接下来就轮到他登场了。
2.3 CallAdapter
最后我们来分析第(3)代码
1 | serviceMethod.adapt(okHttpCall); |
CallAdapter<T>#adapt(Call<R> call)
函数负责把 retrofit2.Call<R>
转为 T
。这里 T
当然可以就是 retrofit2.Call<R>
,这时我们直接返回参数就可以了,实际上这正是 DefaultCallAdapterFactory
创建的 CallAdapter
的行为。在Android平台上默认就是ExecutorCallAdapterFactory
到这里,一个基本的网络请求的过程就算分析完成了。