**本文总结基于Retrofit 2.4.0**
GitHub: [https://github.com/square/retrofit](https://note.youdao.com/)
官方文档: [https://square.github.io/retrofit/](https://note.youdao.com/)
Retrofit 底层是基于OkHttp的进行网络请求的一种封装库。
其实各类大佬博客,公众号,学习网站对Retrofit框架都有详细解读和完美分析了,菜鸟与我,对大佬之敬佩之膜拜,如滔滔江水,延绵不绝,但是,技术是大家的,文章是别人的,带来的结果就是理解但不深刻,掌握但不全面。所以来个自我总结,与人分享,才能共同进步,系不系 O(∩_∩)O
分为以下三大步来总结
**1 Retrofit的使用方式**
**2 Retrofit的源码总结**
**3 Retrofit的原理总结**
# Retrofit的使用方式
直接使用官网例子
第一步:肯定添加一个Retrofit依赖了
compile 'com.squareup.retrofit2:retrofit:2.4.0'
![image](https://www.z4a.net/images/2018/10/22/WX20181022-1633252x.png)
当然也可以直接复制依赖。
第二步:创建一个Retrofit对象,并指定api的域名。
```
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
//这是通过一个Builder模式来构建Retrofit对象的。
//这里说一下我理解的构造着模式的好处吧,总结两点:
//1. 将一个对象的构建和它的表示进行分离,比如一个对象很多属性需要初始化,
//可以通过Builder一键配置。链式调用,方便简洁。
//2. 直接创建对象,对象属性依次初始化,比如
//Person person = new Person();
//person.setName("小吴渐渐");
//person.setAge("27");
//出现的问题是对象已经创建,内存空间,
//系统资源都已经配置好了,小吴渐渐这个人本来是15岁的小鲜肉,突然变成了27岁的老腊肉了,
//系统就需要把以前的资源擦除,重新配置资源这样就带来了性能问题了。
//而 Builder模式是将所有的属性事先配置好,最后通过build一下,一次性完成所有的资源配置。
```
第三步:根据api声明一个java接口,通过java注解来描述这个api
public interface GitHubService {
@GET("users/{user}/repos")
Call> listRepos(@Path("user") String user);
}
//List是根据接口返回的json声明需要的返回值类型
//本来是Response,可是我们需要具体的返回值对象,所以Retrofit支持转换器工厂配置addConverterFactory()
所以第二步可以这样写,这个时候需要添加Gson支持,添加依赖方式参照第一步
compile 'com.squareup.retrofit2:converter-gson:2.4.0'
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create(new Gson()))
.build();
第四步:通过retrofit创建这个接口对象
GitHubService gitHubService = retrofit.create(GitHubService.class);
Call> repos = gitHubService.listRepos("octocat");
最后一步:网络请求
//同步请求(在原来的线程中执行)
repos.execute();
//异步请求(在新的线程中执行)看字面意思是一个队列,但多个请求同时请求时,
//并不是排队进行的,而是并行的。当请求数特别多的时候,考虑网络性能的原因,
//会等待其他网络请求完成时,再去执行。
repos.enqueue(new Callback>() {...);
# Retrofit的源码总结
**看Retrofit.Builder源码**
Builder(Retrofit retrofit) {
platform = Platform.get();
callFactory = retrofit.callFactory;
baseUrl = retrofit.baseUrl;
......
callbackExecutor = retrofit.callbackExecutor;
}
//懵逼状态,也不知道这些初始化变量有啥用,暂时放下Builder
**往下看retrofit.create(GitHubService.class);,这个方法创建了接口的实例对象,这里的疑问就是接口对象是怎么实例化的,所以下面的代码是Retrofit整个结构的核心**
public T create(final Class service) {
//验证传入的service是否是接口,且是否是原生接口也就是不能是继承其他接口的接口,
//其实做的事情就是类型校验
Utils.validateServiceInterface(service);
//对你service中的所有声明的合法性,是否需要提前验证,
//这样做的目的是接口创建的一瞬间进行集中验证,能够及早
//发现代码错误,但是不利于性能,因为每个地方都要验证的话,会造成卡顿。
//一般是关闭的。
if (validateEagerly) {
eagerlyValidateMethods(service);
}
//真正的核心代码是下面这行,是的,只有一行,网上很多解释
//就是通过动态代理实现的,怎么就实现了,大多都是略过了,直接把代码抽出来单独看,请往下⬇️。
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod
这行代码拎出来就是:
**return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class>[] { service },
new InvocationHandler(){...});**
这行代码有三个参数
### 1 service.getClassLoader:
创建任何类的时候都需要提供一个类加载器,将这个类加载进来,这里直接传入接口所在的类加载器。
### 2 new Class>[] { service }:
提供你所创建的所有接口,new Class>[] { service }这个方法的作用就是将你提供的所有接口都实现到一个类中,不过一般只有一个接口,也就是你所声明的所有API注解描述都在一个Service接口中。耶?关键你怎么就实现到一个类中啊,没看到啊,关键在第三个参数。
### 3 new InvocationHandler() {...}
第三个参数是一个匿名内部类,实现了invoke回调方法,这里的作用是传入一个InvocationHandler对象,在需要的时候,调用invoke方法;
这里最关键的是Proxy.newProxyInstance方法通过这三个参数做哪些事。第一会创建一个对象,这个对象会实现你的接口,并重写接口中声明的抽象方法,同时传入一个InvocationHandler对象,**伪代码**如下:
public class RetrofitService implements GitHubService {
InvocationHandler mInvocationHandler = new InvocationHandler() {
......
invoke(xxxx){
......
}
......
});
@Override
public Call> listRepos(String user) {
try {
//获取你声明的接口中需要调用的方法信息,你调用哪个方法就获取哪个方法,毕竟接口中不止一个方法,是吧。
Method method = GitHubService.class.getMethod("listRepos");
return (Call>)mInvocationHandler
.invoke(this, method, xxx);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
......
}
}
Proxy.newProxyInstance方法方法就是做的这个事,retrofit.create(GitHubService.class);方法实际上创建一个Service接口的实现类的对象,当调用接口中声明的方法的时候,就会通过InvocationHandler对象调用invoke方法,并传入接口中声明的方法信息(包括注解,参数,返回值类型),返回了一个Retrofit的Call>对象,这里的疑问是invoke方法,也就是InvocationHandler
.invoke(this, method, xxx);这个代理又做哪些事?
回头看一下invoke方法被实现的地方,在Proxy.newProxyInstance()的第三个参数中,直接把第三个参数的回调方法抽出来看,如下:
invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
private final Platform platform = Platform.get();
//getDeclaringClass()意思是声明的方法在哪个类中声明的,比如onCreate()方法是在MainActivity中声明的。
//下面这行,如果方法声明所在的类是object.class那么就不改写这个方法,直接返回。
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//platform这里确定平台,分别有Android Java8 默认Platform
//下面这行,确定接口默认的方法的实现的平台, 这一行和上面一行都是保证程序的兼容性,让程序不出错而已
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
// 下面这三行重要代码看来是关键了,单独抽出来看看
// 第1行重要代码
ServiceMethod serviceMethod =
(ServiceMethod) loadServiceMethod(method);
// 第2行重要代码
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
// 第3行重要代码
return serviceMethod.adapt(okHttpCall);
}
});
### 第1行重要代码 ServiceMethod
ServiceMethod 官方注释: /** Adapts an invocation of an interface method into an HTTP call. */
看意思是将接口的方法适配到一个HTTP call中,不知所云,反正不知道干啥用的,接着看loadServiceMethod(method)的实现,代码如下:
ServiceMethod, ?> loadServiceMethod(Method method) {
// serviceMethodCache是一个Map>,用map来做Cache非常常见
ServiceMethod, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
// 如果没有就去创建ServiceMethod,然后放入map中,抽出来看ServiceMethod.Builder里面的实现,如下
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
Builder(Retrofit retrofit, Method method) {
// retrofit是一个总管了,这本来就是一个Retrofit框架是不是
this.retrofit = retrofit;
// 根据api定义接口中的方法
this.method = method;
// 方法中每个注解信息
this.methodAnnotations = method.getAnnotations();
// 定义方法的返回值类型
this.parameterTypes = method.getGenericParameterTypes();
// 方法中每个参数和参数注解的信息
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
......
public ServiceMethod build() {
// 这个暂时不知道干啥的
callAdapter = createCallAdapter();
// calladapter 的响应类型中的泛型,比如 Call 中的 User
responseType = callAdapter.responseType();
if (responseType == Response.class || responseType == okhttp3.Response.class) {......}
// 点进去看看 ⬇
responseConverter = createResponseConverter();
for (Annotation annotation : methodAnnotations) {
// 解析每一个方法的注解
parseMethodAnnotation(annotation);
}
......
}
private Converter createResponseConverter() {
// 获取声明方法的注解
Annotation[] annotations = method.getAnnotations();
try {
// 根据返回值类型和方法注解获取Converter对象
// responseConverter做的事情就是
// 将网络请求的数据转化为声明接口方法中的返回泛型
return retrofit.responseBodyConverter(responseType, annotations);
}
......
}
//在ServiceMethod可以直接找到调用的地方
R toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
}
哦,这么一看有点明白了,ServiceMethod做的事情就是解析我们声明的接口中的方法,比如方法注解,返回值类型,参数和参数注解等。
### 第2行重要代码 OkHttpCall
通过解析我们定义的方法而生成的ServiceMethod对象传入到OkHttpCall的构成方法中返回了一个OkHttpCall的对象,来看看里面的实现,可以看出OkHttpCall实现了Call,而这个Call实际上就是Retrofit使用方式的第四步中Call> repos = gitHubService.listRepos("octocat");,注意:是 Retrofit 中的 Call 而不是 OkHttp 中的 Call ,而这个Call就是声明Service接口中定义的
@GET("users/{user}/repos")
Call> listRepos(@Path("user") String user);
final class OkHttpCall implements Call {
OkHttpCall(ServiceMethod serviceMethod, @Nullable Object[] args) {
//serviceMethod传进来仅仅做了一些变量初始化,接着看invoke方法中最后一行代码,往下。
this.serviceMethod = serviceMethod;
this.args = args;
}
}
### 第3行重要代码 serviceMethod.adapt(okHttpCall)
根据**第2行重要代码**生成的 OkHttpCall对象,终于知道我们的Call对象是怎么来的了,怎么还要作为参数传入到serviceMethod的adapt()方法中,没办法,接着往下看
T adapt(Call call) {
//看到这个callAdapter,是不是很熟悉,就是在第1行重要代码中
//通过 build 生成 ServiceMethod 对象的地方,当时猜测callAdapter做类型转换的事情
return callAdapter.adapt(call);
}
现在找找callAdapter是如何创建的,这里 ***ServiceMethod.Builder<>(this, method).build();***
public ServiceMethod build() {
//现在来看看createCallAdapter()的具体实现
callAdapter = createCallAdapter();
......
}
⬇⬇
private CallAdapter createCallAdapter() {
......
// 获取方法返回值类型
Type returnType = method.getGenericReturnType();
......
// 获取方法所有的注解信息
Annotation[] annotations = method.getAnnotations();
try {
//noinspection unchecked
//巴拉巴拉,一坨代码,核心代码原来在这里,传入上面两个初始化参数,生成了CallAdapter,继续看内部实现
return (CallAdapter) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) {
......
}
}
⬇⬇
public CallAdapter, ?> callAdapter(Type returnType, Annotation[] annotations) {
//继续点进去看
return nextCallAdapter(null, returnType, annotations);
}
⬇⬇
public CallAdapter, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
......
// 原理CallAdapter是从callAdapterFactories集合中取出Factory,再根据返回值类型,注解信息获取到的。
// Factory是CallAdapter的一个内部类,callAdapterFactories又是如何获取的呢?接着往下看
CallAdapter, ?> adapter = callAdapterFactories.get(i)
.get(returnType, annotations, this);
......
}
⬇⬇
public final class Retrofit {
......
final List callAdapterFactories;
Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
List converterFactories, List callAdapterFactories,
@Nullable Executor callbackExecutor, boolean validateEagerly) {
......
// 在这里,是通过作为Retrofit的构造方法的参数传进来的,再看看哪里调用了 Retrofit 的构造方法
this.callAdapterFactories = callAdapterFactories;
......
}
⬇⬇
//看这个是不是很熟悉,就是我们的Retrofit对象通过Buidle模式创建的时候调用的地方
public Retrofit build() {
//callAdapterFactories找的好辛苦,原来在这里实现的
// 这里有两行
//这一行会将一个空的callAdapterFactories添加进来
List callAdapterFactories =
new ArrayList<>(this.callAdapterFactories);
//原来是通过defaultCallAdapterFactory方法获取callAdapterFactories
// 接下来看看 defaultCallAdapterFactory()方法的实现
callAdapterFactories.add(
platform.defaultCallAdapterFactory(callbackExecutor));
......
//在这里调用了Retrofit的构造方法,并传入了callAdapterFactories
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
⬇⬇
CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
if (callbackExecutor != null) {
//继续点进去看
return new ExecutorCallAdapterFactory(callbackExecutor);
}
return DefaultCallAdapterFactory.INSTANCE;
}
//这个类继承了CallAdapter.Factory也
//就是通过callAdapterFactories集合获取到的对象
final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
......
ExecutorCallAdapterFactory(Executor callbackExecutor) {
this.callbackExecutor = callbackExecutor;
}
// 这里就是上述方法中调用get方法真正获取CallAdapter对象
@Override
public CallAdapter, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
......
return new CallAdapter>() {
@Override public Type responseType() {
return responseType;
}
// 最重要的关键点,就是动态代理中invoke方法的最后一行重要方法传入HttpCall对象,
@Override public Call adapt(Call call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
static final class ExecutorCallbackCall implements Call {
final Executor callbackExecutor;
......
@Override public void enqueue(final Callback callback) {
checkNotNull(callback, "callback == null");
//终于知道enqueue是如何调用的了,delegate是一个Call对象,
//是invoke方法中第3行重要代码中传入的HttpCall对象,而HttpCall是实现Call接口并重写了enqueue方法的,等下介绍响应部分源码
delegate.enqueue(new Callback() {
@Override public void onResponse(Call call, final Response response) {
// 最最重要的是这个了callbackExecutor
// 回调方法执行器,是Executor对象,和线程相关的类,
// 来看看callbackExecutor的实现地方
callbackExecutor.execute(new Runnable() {
@Override public void run() {
......
//callback就是自己调用enqueue方法传入的对象
callback.onFailure(ExecutorCallbackCall.this, new
......
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}
......
});
}
callbackExecutor的对象是通过调用ExecutorCallAdapterFactory构造方法传入
ExecutorCallAdapterFactory(Executor callbackExecutor) {
this.callbackExecutor = callbackExecutor;
}
//看看哪里调用了ExecutorCallAdapterFactory方法
⬇
//就是我们的Retrofit对象通过Buidle模式创建的时候调用的地方,也是callAdapterFactor初始化的地方
public Retrofit build() {
......
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
//callbackExecutor是在这里返回的,前面说过,
//platform是java8和Android都有的平台,看看在哪里继承了Platform,
//并调用了defaultCallbackExecutor()方法
callbackExecutor = platform.defaultCallbackExecutor();
}
List callAdapterFactories =
new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
......
⬇
//在这里,Android平台继承了Platform,并调用了defaultCallbackExecutor方法
static class Android extends Platform {
@Override public Executor defaultCallbackExecutor() {
// MainThreadExecutor,是不是很熟悉了,想想应该是做主线程切换的作用,
//MainThreadExecutor看看具体的实现
return new MainThreadExecutor();
}
⬇
static class MainThreadExecutor implements Executor {
// 获取主线程的Handler
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
// 通过handler将线程切换到主线程
handler.post(r);
}
}
```
现在回头看看创建Retrofit的build方法,里面的各种属性就应该很好理解了O(∩_∩)O
```
public Retrofit build() {
.....
// callFactory就是OkHttpClient,真正执行网络请求的的工厂
callFactory = new OkHttpClient();
.....
// 线程相关的类,通过它可以获取到CallAdapter
callbackExecutor = platform.defaultCallbackExecutor();
......
// CallAdapter的工厂,将执行环境切换到主线程中的作用,当然,并不是只做这个,
// 还可以做 Rxjava 的适配,可以将线程切换交给Rxjava来处理,
// 你如果没有支持的话,默认使用ExecutorCallAdapterFactory
// 接口中会根据声明的每个方法的注解和参数以及返回值类型创建每个CallAdapter
List callAdapterFactories =
new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// 数据转换工厂
List converterFactories =
new ArrayList<>(1 + this.converterFactories.size());
......
}
请求过程大致结构和过程看过来了,其中细节特多,最后,第三行重要代码多的够够的,整套流程下来,差不多明白了serviceMethod的adapt(),主要做线程切换和Rxjava的适配。
### 响应部分源码
上面说了HttpCall是继承了Call接口,并重写了enqueue方法,最后通过handler将执行环境切换到主线程的。说了这么多,OkHttp在哪里呢?来看看HttpCall调用enqueue()的地方。
@Override
public void enqueue(final Callback callback) {
okhttp3.Call call;
......
// 创建了OkHttp的Call的对象,上面说的Call包括 HttpCall 都是 Retrofit 的 Call,
// 这里是 Retrofit 和 OkHttp 的地方
call = rawCall = createRawCall();
......
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
......
response = parseResponse(rawResponse);
......
}
Response parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
......
int code = rawResponse.code();
// 响应码 小于200 或 大于300 都算失败,一般 Okhttp内部就已经解决了,基本上失败情况到不了这里
if (code < 200 || code >= 300) {
......
}
// 返回一个没有body的结果,body就是OkHttp响应报文中的body
if (code == 204 || code == 205) {
rawBody.close();
return Response.success(null, rawResponse);
}
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
// 这里将请求下来的body转化为返回值中对应的泛型,并返回。
T body = serviceMethod.toResponse(catchingBody);
return Response.success(body, rawResponse);
}
......
}
}
### 最后
花了大概两天时间,整理了一下,把总体架构梳理一篇,尤其动态代理怎么做的,重点说了一下,细节很多,自己写的都晕了,很多说的不够好。仅仅作为自己的总结,学习,记录一下,如有错误,多多指教。Retrofit框架超级厉害,大量封装了建造者模式、装饰者模式,值得学习。