拆轮子系列 - 如何由浅入深探索 Retrofit 源码?
前言
相信点开文章的你,多少也知道或者使用过Retrofit框架吧。如果你有一颗想对源码一探究竟的心,却不知如何入手。笔者一直也有这样的困惑,也正在努力总结出一套有效的分析源码方法,希望本文的拆轮子思路能给你带来一些帮助。
本文记录了笔者基于 Retrofit 2.1.0 源码的学习分析过程,文中拆解思路很大程度受到Stay4it所制作的教程启发(良心教程,文末有链接,配合视频食用本文效果更佳),故跟随该教程结合自身见解进行一番记录,如有错漏,恳请指正。
探索方式:
- 学会用该框架,动手写Demo,理解框架应用场景,基本特点(前提)。
- 利用网络资源,搜寻多篇前人写过的拆轮子资源,下载源码,跟随资源进行源码跟踪,如果不动手,我认为是很难将框架理解的。
- 阅读源码时,学会总结:从Retrofit一般使用方式入手,通过断点调试,观察源码执行顺序,忽略非重要代码,摸清源码主线实现思路后,再深入探索其中的细节实现。
- 回顾与整理,最后再过一遍思路,若走通了,那么框架的大概就理解了,同时整理笔记,便于日后忘了回来查看。
网络请求框架的基本流程
- 构建Request,入队
- 进入Executor执行,Looper不断循环,拿到Request执行
- 执行结果的解析与返回
Retrofit 概述(WHAT)
一个在Android/Java平台上运行的type-safe HTTP Client,其中type-safe是通过声明泛型来保证的,支持RxJava,解耦程度高,基于 Retrofit当前最新版2.1.0,即将出版2.2.0。(2017.1.)
构建Request
Retrofit通过注解来构建Request,所有的参数都可以简单配置完毕,上层不需要关心底层使用何种方式实现构建Request过程。
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
实现Executor
实现上述声明的接口,得到可以做具体请求操作的实现类。
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
GitHubService service = retrofit.create(GitHubService.class);
相关概念
CallAdapter:Adapter a Call into the type of T.(将一个Call适配为另外一个Call的适配器接口)
- Type responseType():将返回的请求转化为参数Type类型
- T adapt(Call<R> call):将一个Call转换成另外一个Call
HTTP Call
调用上述实现类的方法即可得到Call,而Retrofit内部使用OkHttp实现HTTP Call,最后通过Converter转换成用户想要的对象体。
Call:An invocation of a Retrofit method that sends a request to a webserver and returns a response.(请求发送与响应返回方法的调用)
Call<List<Repo>> repos = service.listRepos("octocat");
主线用例
// 源码剖析 - 步骤1~4
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://gank.io/")
.addConverterFactory(GsonConverterFactory.create())
.build();
// 源码剖析 - 步骤5~6
Api api = retrofit.create(Api.class);
// 源码剖析 - 步骤7
Call<BaseModel<ArrayList<Benefit>>> call = api.defaultBenefits(20, page++);
call.enqueue(new Callback<BaseModel<ArrayList<Benefit>>>() {
@Override
public void onResponse(Call<BaseModel<ArrayList<Benefit>>> call, Response<BaseModel<ArrayList<Benefit>>> response) {
if (action == PullRecycler.ACTION_PULL_TO_REFRESH) {
mDataList.clear();
}
if (response.body().results == null || response.body().results.size() == 0) {
recycler.enableLoadMore(false);
} else {
recycler.enableLoadMore(true);
mDataList.addAll(response.body().results);
adapter.notifyDataSetChanged();
}
recycler.onRefreshCompleted();
}
@Override
public void onFailure(Call<BaseModel<ArrayList<Benefit>>> call, Throwable t) {
recycler.onRefreshCompleted();
}
}
);
Retrofit主线源码剖析(HOW - Part 1)
- Retrofit对象的创建
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://gank.io/")
.addConverterFactory(GsonConverterFactory.create())
.build();
-
build()方法内部
构建Retrofit对象主要思路:1、创建callbackExecutor(内部获取主线程MainLooper来构建Hanlder,其execute方法本质是Handler.post(runnable),待用于线程切换);2、构建adapterFactories集合,将defaultAdapterFactory加入其中(ExecutorCallAdapterFactory类,线程切换关键实现,内部持有OkHttp代理delegate,在delegate.enqueue中的onRespond方法内使用刚刚创建的callbackExecutor.execute方法,从而实现线程切换)
public Retrofit build() {
...
// 创建OkHttp,目前Retrofit只支持OkHttp
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
// 创建Executor,见步骤3
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
// 对adapters进行保护性拷贝,并且加入默认的call adapter(使用上面创建的Executor来构建,可以认为是把主线程中的Handler传入)
// 构建adapterFactories集合,将defaultAdapterFactory加入其中,见步骤4
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
// 对converters进行保护性拷贝
// 一般传入的为GsonConverterFactory对象,其作用主要是将json转换成java对象
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
//最终完成Retrofit对象构建
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
- Executor的获取 - platform.defaultCallbackExecutor();
static class Android extends Platform {
@Override
public Executor defaultCallbackExecutor() {
// 返回MainThreadExecutor
return new Platform.Android.MainThreadExecutor();
}
@Override
CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
static class MainThreadExecutor implements Executor {
// 从主线程得到MainLooper,构建Handler
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable r) {
// execute方法本质:通过handler,在主线程上执行该runnable
handler.post(r);
}
}
}
- 详解 platform.defaultCallAdapterFactory(callbackExecutor) - 线程切换的关键
// platform.defaultCallAdapterFactory(callbackExecutor)
CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
if (callbackExecutor != null) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
return DefaultCallAdapterFactory.INSTANCE;
}
// ExecutorCallAdapterFactory构造方法
// ExecutorCallAdapterFactory通过传参,得到callbackExecutor
ExecutorCallAdapterFactory(Executor callbackExecutor) {
this.callbackExecutor = callbackExecutor;
}
// get方法,创建并返回Android平台默认CallAdapter
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call<Object> adapt(Call<Object> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
//----------------------------分割线-----------------------------------
// ExecutorCallAdapterFactory内部类ExecutorCallbackCall中enqueue方法,子线程转换为主线程的关键
@Override
public void enqueue(final Callback<T> callback) {
if (callback == null) throw new NullPointerException("callback == null");
// 子线程中执行,此处的delegate本质是OkHttpCall(主要用于对接OkHttp框架)
delegate.enqueue(new Callback<T>() {
@Override
public void onResponse(final Call<T> call, final Response<T> response) {
// 响应请求,调用callbackExecutor的execute
// 从步骤3中可知,该方法本质是调用主线程的Handler执行runnable
// 包裹用户传入的callback,从而实现线程切换
callbackExecutor.execute(new Runnable() {
@Override
public void run() {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException oncancellation.
callback.onFailure(call, new IOException("Canceled"));
} else {
callback.onResponse(call, response);
}
}
});
}
@Override public void onFailure(final Call<T> call, final Throwable t) {
// 包裹用户传入的callback,从而实现线程切换
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(call, t);
}
});
}
});
}
-
详解:retrofit.create(Api.class)
创建接口实现类:创建并返回一个会拦截接口方法的动态代理对象实例 - 接口方法被调用时,会被其拦截,内部将接口方法适配成HTTP Call,再构造对应的OkHttpCall,最后通过CallAdapter.adapt()转换成Retrofit适用的call delegates(即ExecutorCallbackCall)。
Api api = retrofit.create(Api.class);
// create方法内部实现,返回一个动态代理实例
public <T> T create(final Class<T> service) {
...
// 该动态代理会对接口方法进行拦截
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
// 创建一个InvocationHandler,接口方法被调用时会被拦截调用
new InvocationHandler() {
private final Platform platform = Platform.get();
// 当Api接口方法被调用时,会调用invoke方法拦截
@Override public Object invoke(Object proxy, Method method, Object... args)
throws Throwable {
...
// 通过解析api方法注解、传参,将接口中方法适配成HTTP Call,详解见步骤6
ServiceMethod serviceMethod = loadServiceMethod(method);
// 拦截下来之后,内部构建一个okHttpCall
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
// 最后通过callAdapter将okHttpCall转换成为Retrofit适用的call delegates(代理),Android平台默认使用ExecutorCallAdapterFactory,adapt返回ExecutorCallbackCall(即步骤4)
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
-
详解 ServiceMethod serviceMethod = loadServiceMethod(method);
ServiceMethod整体思路: 内部主要是将方法中的注解取出,转换成HTTP Call的逻辑,暂且不深究。
下面看loadServiceMethod方法的实现
// 内部有缓存以提高性能,避免重复解析 - 使用LinkedHashMap来存储ServiceMethod,与接口中方法一一对应
private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result;
synchronized (serviceMethodCache) {
// 通过传入的方法,从Map中取出对应的ServiceMethod
result = serviceMethodCache.get(method);
if (result == null) {
// 如果还没有实现,则构造一个ServiceMethod实例放入Map中
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
- ** 回到主线**,retrofit.create()方法创建好实现类后,调用接口方法获得Call,前面步骤5已经说道,当接口方法被调用时候,会被拦截并且转换成HTTP Call。
下面我们使用call进行enqueue操作:此处的call,即ExecutorCallbackCall,它有execute(同步)、enqueue(异步)两个方法,其中enqueue方法,可达到子线程请求,成功后切换回主线程的效果(原理 - 步骤4),免去了开启线程、使用handler跨线程通信的操作。
Call<BaseModel<ArrayList<Benefit>>> call = api.defaultBenefits(20, page++);
call.enqueue(new Callback<BaseModel<ArrayList<Benefit>>>() {
// 该处的onResponse方法已经转换到主线程上了,而转换关键在于Retrofit对象构建时,defaultAdapterFactory内部实现,见步骤2->步骤4
@Override
public void onResponse(Call<BaseModel<ArrayList<Benefit>>> call, Response<BaseModel<ArrayList<Benefit>>> response) {
...
}
@Override
public void onFailure(Call<BaseModel<ArrayList<Benefit>>> call, Throwable t) {
...
}
}
-
Retrofit主线流程总结:
1. Retrofit对象的构建 - Retrofit.Builder()...build():①构建OkHttpClient,目前Retrofit仅支持OkHttpClient;②构建Executor:优先根据用户提供的callBackExcecutor来构建,若用户没有提供,则提供defaultCallbackExecutor(其内部会获取MainLooper构建handler,execute方法直接handler.post(runnable),实现在主线程上的操作);③使用executor来构建adapterFactories集合,优先将用户提供的adapterFactory加入到其中,再加上defaultCallAdapterFactory(传入②创建的callbackExecutor,defaultCallAdapterFactory内部持有OkHttpCall,在其enqueue方法中的onResponse方法调用defaultCallbackExecutor.execute方法,从而实现线程切换操作);④最终使用Retrofit构造方法构建Retrofit实例对象
2. Retrofit接口方法的实现方式 - retrofit.create(接口名.class):①create方法创建并返回动态代理对象实例,动态代理对象内部会拦截接口方法的调用②动态代理内部通过ServiceMethod将接口方法适配成HTTP Call,再构造对应的OkHttpCall,最后通过CallAdapter转换成Retrofit适用的call delegate(ExecutorCallbackCall)。
3. 使用动态代理(接口实现类)调用接口方法得到Call、使用call.enqueue进行异步请求:①调用接口方法时,动态代理对象(接口实现类)内部拦截;②调用call.enqueue,内部会调用ExecutorCallAdapter的enqueue方法,enqueue中onResponse方法调用defaultCallbackExecutor.execute方法,使用主线程Handler.post(runnable)从而实现线程切换操作。
-
Retrofit主线流程总结图解(从上往下阅读):
Retrofit源码深入探索(HOW - Part 2)
- retrofit.create()方法中一段令人疑惑的代码,却是Retrofit工作主要代码:
// ①创建ServiceMethod,见深入探索步骤2
ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method);
// ②传入ServiceMethod构造OkHttpCall,使用构造方法传入成员变量
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
// ③又将构造好的OkHttpCall传回,通过ServiceMethod中的callAdapter来进行转换,见步骤4
return serviceMethod.callAdapter.adapt(okHttpCall);
-
解析ServiceMethod:Adapts an invocation of an interface method into an HTTP call - 将接口中的方法适配成HTTP Call
loadServiceMethod内部通过Builder,build()方法创建:内部创建了CallAdapter(例:defaultCallAdapterFactory - 将Http Call 转成Retrofit中的Call->调用okHttp3.Call->线程切换)、Converter(请求结果转换器,例:Gson)、callFactory(okhttp3.Call.Factory - 对接okHttp)、
public ServiceMethod build() {
// callAdapter的创建
callAdapter = createCallAdapter();//追踪代码可知:本质通过retrofit.nextCallAdapter方法创建,见步骤3
responseType = callAdapter.responseType();
...
// 创建ResponseConverter(转换器 - 对象与Http表示形式相互转换)
responseConverter = createResponseConverter();
// 解析注解参数,逻辑不必深究
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
...
return new ServiceMethod<>(this);
}
// 构造方法,内部参数基本都由Retrofit提供
ServiceMethod(Builder<R, T> builder) {
// 负责创建HTTP请求,一个可以执行的HTTP请求(okHttp3.Call),仅支持OkHttpClient
this.callFactory = builder.retrofit.callFactory();
// 将Retrofit中的Call<T>转为T(Retrofit中的Call ≠ okHttp中的Call,前者表示retrofit接口方法调用,内部通过后者实现,最后通过)
this.callAdapter = builder.callAdapter;// 将响应类型适配成用户指定的类
this.responseConverter = builder.responseConverter;// 对象与Http表示形式相互转换的转换器
this.parameterHandlers = builder.parameterHandlers;// 解析接口注解参数
...// 略去非重点关注成员变量
}
- CallAdapter的创建:遍历adapterFactories,找到并返回合适的adapter
public CallAdapter<?, ?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
...
// 遍历adapterFactories,找到可以接收指定类型的adapter
for (int i = start, count = adapterFactories.size(); i < count; i++) {
// 通过get方法,获得相匹配的类型
CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
// 找到合适adapter,返回
return adapter;
}
}
...
}
//下面看看一般的adapterFactories源码
//1、ExecutorCallAdapterFactory中的get方法
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
// 如果返回类型为Call类型,则使用它
if (getRawType(returnType) != Call.class) {
return null;
}
...
}
//2、RxJavaCallAdapterFactory、RxJavaCallAdapterFactory中的get方法是Observable类型(源码略显复杂掠过)
-
解析serviceMethod.callAdapter.adapt方法:因callAdapter类型而异,ExecutorCallAdapterFactory适配的是ExecutorCallbackCall类型,而RxJava适配的是Observable类型
注意:无论是什么类型的callAdapter,最终都会调用OkHttpCall中的enqueue、execute方法,把实际的工作交给OkHttp来做,详见步骤5
// ExecutorCallAdapterFactory
@Override public Call<Object> adapt(Call<Object> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
// RxJavaCallAdapter
@Override public Object adapt(Call<R> call) {
OnSubscribe<Response<R>> callFunc = new CallOnSubscribe<>(call);
OnSubscribe<?> func;
// 构造订阅者func逻辑,省略...
// 通过func构造Observable
Observable<?> observable = Observable.create(func);
// Observable配置逻辑,省略...
return observable;
}
- 解析OkHttpCall调用链:OkHttp的包装类,与OkHttp对接,实现了Retrofit中的Call接口,内部使用OkHttp框架来进行实际操作,解析好数据后再调用传入的callbackA -(内部通过Execute实现线程切换)->调用用户传入的callbackInMainThread(漫长的一个调用链..)
// 从上面分析可知,调用接口定义方法返回ExecutorCallbackCall
// call.enqueue(callbackInMainThread); 调用其enqueue方法,内部持有OkHttpCall 作为 delegate
// 将callbackInMainThread包裹executor实现线程切换,生成callbackA
// delegate.enqueue(callbackA); 上面的方法内部会调用delegate.enqueue方法以对接OkHttp框架
// 下面看OkHttpCall的enqueue方法(OkHttp框架里的方法,与Retrofit无关)
@Override public void enqueue(final Callback<T> callback) {
...
okhttp3.Call call;
...
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {
Response<T> response;
try {
// onResponse时候进行数据转换,关键点:Converter (下方附有调用链)
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
callSuccess(response);
}
...
// 请求失败调用callbackA.onFailure -(内部线程切换)-> callbackInMainThread.onFailure
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
// 响应成功调用callbackA.onResponse -(内部线程切换)-> callbackInMainThread.onSuccess或onFailure
private void callSuccess(Response<T> response) {
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
}
// 数据转换调用链:parseResponse -(关键调用)-> serviceMethod.toResponse -> GsonRequestBodyConverter.convert
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
...
T body = serviceMethod.toResponse(catchingBody);
...
}
Retrofit中的设计模式,解耦方式(WHY)
Retrofit中涉及不少的设计模式,笔者能力有限,设计模式方面知识储备不足,仍需继续努力,这里暂且给出设计模式定义与链接,作初步认识。
门面模式(Facade Pattern)
Retrofit - retrofit.create()
定义:外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。门面模式又称为外观模式,它是一种对象结构型模式。
传送门:xingjiarong - 门面模式
工厂模式
Retrofit中的三大工厂 - okhttp3.Call.Factory,CallAdapter.Factory 和 Converter.Factory
定义:又称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式(同属于创建型模式的还有工厂方法模式,抽象工厂模式,单例模式,建造者模式)。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
传送门:xingjiarong - 简单工厂模式、xingjiarong - 抽象工厂模式
装饰模式
ExecutorCallbackCall类:在源“OkHttpCall”操作时,进行线程切换操作
定义:动态地给一个对象增加一些额外的职责(Responsibility),就增加对象功能来说,装饰模式比生成子类实现更为灵活。其别名也可以称为包装器(Wrapper),与适配器模式的别名相同,但它们适用于不同的场合。根据翻译的不同,装饰模式也有人称之为“油漆工模式”,它是一种对象结构型模式。
传送门:design-patterns - 装饰模式
动态代理
ExecutorCallbackCall中的delegate的动态设置,从而针对不同代理采用不同方法
定义:给某个对象提供一个代理对象,并由代理对象控制对于原对象的访问,即客户不直接操控原对象,而是通过代理对象间接地操控原对象。
传送门:xiazdong - 代理模式及Java实现动态代理
适配器模式
CallAdapter,各种适配器,将一个东西适配成一个适合我们使用的东西
定义:适配器模式将一个类的接口,转化成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。
传送门:xingjiarong - 适配器模式
策略模式
CallAdapter内部还夹杂着策略模式?
定义:定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)。
传送门:xingjiarong - 策略模式、design-patterns - 策略模式
Stay的详细分析:Retrofit分析-经典设计模式案例