今天我来记录一下我对Retrofit框架的理解。不得不说,Retrofit的架构设计极其优秀,既保证了使用上的方便,又高度解耦。同时Retrofit又是学习设计模式的不二典范,里面使用的设计模式数不胜数。今天我们来详细的剖析这个框架。
本文参考资料:
1. 这是一份很详细的 Retrofit 2.0 使用教程(含实例讲解 )
2. Android:手把手带你深入剖析 Retrofit 2.0 源码
由于Retrofit里面涉及到RxJava和Gson相关知识,所以在阅读本文之前,最好是对RxJava原理有一定的了解。至于Gson,只要会用就行,其实我也不太了解Gson的原理😂。
1. 先逼逼几句
众所周知,Retrofit是基于OkHttp设计的一个网络请求框架。其实说Retrofit是一个网络不是那么准确,准确来说,Retrofit就是OkHttp的一个外壳,Retrofit的底层网络请求使用就是OkHttp。
同时,Retrofit完全兼容RxJava,这使得它的使用范围进一步扩大,因为这个特性,进一步促进演变近几年比较火的Android架构框架 - RxJava + Retrofit + MVP
。
本文打算从Retrofit的基本使用开始,深入分析Retrofit的整个工作流程,包括线程调度、与RxJava兼容等等。
2. Retrofit组成部分
Retrofit分为4个部分,我们来看看。
名字 | 含义 |
---|---|
自定义的请求接口 | 主要定义一些网络请求基本参数,比如请求方式(get或者post),表单等等 |
由请求接口生成OkHttp的Request | 根据自定义的请求接口,生成对应的可以执行的Request ,此过程只要在ServiceMethod 里面完成 |
网络请求执行器-Call | 用来执行生成的Request ,在Retrofit里面,使用了装饰者模式,OkHttpCall 只是外壳,内部的Call 才是真正执行Request 的 |
数据转换器-Converter | 主要是将返回的Response 解析成为我们想要的Java类对象 |
提一句,Retrofit是适合于Restful API的网络请求框架,如果想要让Retrofit支持非Restful API,可以参考这一篇文章:如何使用Retrofit请求非Restful API(悄悄的给你们说一句,这个问题,我在腾讯面试被问过🙄)
我们先大体看看Retrofit怎么通过这四个部分来进行工作。
3. 基本使用
本文简单介绍一下Retrofit的基本使用,让大家有一个印象。但是毕竟不是初级文章,不会在方面花很多的时间。
首先需要定义一个接口。
public interface Service {
@POST("getSongPoetry")
@FormUrlEncoded
Observable<Bean> getCall(@Field("page") int page, @Field("count") int count);
}
然后创建一个Retrofit
的对象。
private Retrofit mRetrofit = new Retrofit.Builder()
.baseUrl("http://api.apiopen.top/")
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
然后通过Retrofit
的对象获得接口的代理对象。
Service service = mRetrofit.create(Service.class);
最后调用对应的接口来请求数据。
service.getCall(1, 20)
.observeOn(Schedulers.newThread())
.subscribeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Bean>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Bean bean) {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
整个Retrofit的网络请求过程就是这样,是不是非常的简单?这里面我们根本不需要考虑线程调度的问题,以及数据解析的问题,Retrofit已经给我们做了。
4. Retrofit
从现在开始,我们正式开始分析Retrofit整个工作流程。我们先来看看Retrofit对象的创建。
private Retrofit mRetrofit = new Retrofit.Builder()
.baseUrl("http://api.apiopen.top/")
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
从这里,我们已经可以看到两个设计模式--建造者模式
和工厂模式
。当然我们也没必要紧张,就是两个的设计模式而已。
这里通过调用Retrofit
一个内部类Builder
一系列的方法,进而初始化了Retrofit
一些必须的对象。
(1).Builder
我们先来看看Builder
类,我们先从它的成员变量开始
private final Platform platform;
private @Nullable okhttp3.Call.Factory callFactory;
private HttpUrl baseUrl;
private final List<Converter.Factory> converterFactories = new ArrayList<>();
private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
private @Nullable Executor callbackExecutor;
private boolean validateEagerly;
变量名 | 类型 | 作用 |
---|---|---|
platform | Platform | 平台的对象,通过调用Platform 的get 方法,可以获得适合当前环境的平台,包括Java8、Android(似乎Retrofit 2.4.0将其他的平台移除了)。Platform 可以通过调用defaultCallAdapterFactory 方法可以获得网络执行适配器的工厂类,调用defaultCallbackExecutor 方法可以获得线程调度的对象 |
callFactory | okhttp3.Call.Factory | 网络请求执行器的工厂类,用来创建网络请求执行器的对象 |
baseUrl | HttpUrl | 网络请求的URL基地址,完整的URL地址应当是baseUrl + relativeUrl 。其中,调用Builder 的baseUrl 方法设置的就是基地址,在接口中@Post 注解里面的值就是relativeUrl
|
converterFactories | List<Converter.Factory> | 数据转换器的数组,当收到Response时,Retrofit会根据接口里面定义的返回类型在converterFactories 里面找到合适的数据转换器,从而将Response转换成为正确的类型。 |
callAdapterFactories | List<CallAdapter.Factory> | 网络请求执行适配器的数组,跟List<CallAdapter.Factory> 一样,会根据接口里面定义的类型来找到合适的适配器。但是二者有所不同,待会会详细的分析。 |
callbackExecutor | Executor | 回调线程池,主要是将结果发送到指定的线程,比如,在Android平台上,肯定是将结果发送到主线程。 |
validateEagerly | boolean | 是否提前将接口里面的方法解析成为ServiceMethod 。至于什么是ServiceMethod ,后面会详细的解释。 |
上表中详细的解释了Builder
每一个成员变量的作用,在Builder
类中,每一个成员变量都有一个对应的方法用来赋值。比如说addCallAdapterFactory
方法可以往callAdapterFactories
添加一个适配器,其他的也是如此。
接下来我们看看Builder
的build
方法。
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories =
new ArrayList<>(1 + this.converterFactories.size());
// Add the built-in converter factory first. This prevents overriding its behavior but also
// ensures correct behavior when using converters that consume all types.
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
哟哟,这个build
方法里面还做了不少的事情的,我们来看重点。
if (callFactory == null) {
callFactory = new OkHttpClient();
}
从这里,我们可以看出来,如果我们设置网络请求执行器,默认就是OkHttpClient
,这个OkHttpClient
在OkHttp
是一个非常核心的类,是网络请求必须的类。这里不对OkHttpClient
进行展开,毕竟是OKHttp
的相关知识。
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
同理,如果回调线程池默认也为该平台的回调线程池。比如说,如果是Android平台,那么肯定是调用这段代码:
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
从MainThreadExecutor
的名字,我们就可以得出结果,肯定是用来回调到主线程的,毕竟在Android中,只有主线程才能更新UI🤓。
至于其他的,都是常规的赋值,这里就不详细讲解了。
在build
方法最后一行代码,创建了一个Retrofit
的对象。我们来看看Retrofit
的构造方法。
Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
List<Converter.Factory> converterFactories, List<CallAdapter.Factory> callAdapterFactories,
@Nullable Executor callbackExecutor, boolean validateEagerly) {
this.callFactory = callFactory;
this.baseUrl = baseUrl;
this.converterFactories = converterFactories; // Copy+unmodifiable at call site.
this.callAdapterFactories = callAdapterFactories; // Copy+unmodifiable at call site.
this.callbackExecutor = callbackExecutor;
this.validateEagerly = validateEagerly;
}
其实也没做什么事情,就是将Builder
的成员变量对应的赋值给Retrofit
。
(2).Retrofit的创建为什么要使用建造者模式?
我们发现,经过一些操作,最终的目的就是创建一个Retrofit
对象,然后给Retrofit
的成员变量赋值,为什么我们需要多一个Builder
,然后绕一大圈来创建一个Retrofit
对象呢?
我首先问一句,在外面写这么一句代码就能创建完整的Retrofit
对象,觉得爽不爽?
private Retrofit mRetrofit = new Retrofit.Builder()
.baseUrl("http://api.apiopen.top/")
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
不用说,肯定爽,首先外部代码简洁,通过调用对应方法来给变量赋值,链式编程方格6的不行。其次,在Retrofit
的构造方法也是非常的简洁,没有各种判断,所有的工作都在Builder
的build
方法做了。
所以,我们从Retrofit
里面得到,如果一个对象得创建需要给很多的成员变量,不妨使用建造者模式,这使得你的代码更加的简洁。外部使用起来也是非常的简单。
(3).create方法
从上面的栗子,我们可以知道,当创建完毕一个Retrofit的对象时,如果想要进行网络请求的话,还必须创建接口的代理对象,也就是通过调用create
方法来获得一个对象。
从我的言语之间,你们应该都知道,create
方法肯定使用了代理模式,要不然何来代理对象
之称。我们来看看create方法的实现。
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(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<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);
}
});
}
哎呀哎呀,懵逼还是懵逼,没错!对于那些Java功底还不够牢固的同学来说,这个方法单单是看一眼就很懵逼,当初我看这个方法时,也是一脸懵逼。
不过,懵逼归懵逼。我想说的是,这段代码是整个Retrofit的画龙点睛之笔,特别是其中的三行代码,都可以称之为神来之笔。
我们先来粗略的看看这段代码。
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
首先是validateEagerly
相关的。第一行代码是验证当前这个Class对象是否合法。至于是否合法说的太笼统了,具体就是判断当前的Class是否是一个接口,并且没有继承接口。总之,就是验证Class是否一个单纯的接口。
然后就是eagerlyValidateMethods
方法的调用,如果validateEagerly
为true的话,那么就调用eagerlyValidateMethods
方法。至于eagerlyValidateMethods
方法里面干了什么,在这里,先不急着说,等后面咱们分析ServiceMethod
类时,咱们再来好好的说道说道🤓。在这里先提一句,eagerlyValidateMethods
方法就是将接口的里面的方法解析成为ServiceMethod
对象,这个也是validateEagerly
变量的作用,之前也说过。
看完了简单的几行代码,接下来的代码就是让人彻底懵逼的代码。说到底,其实也没啥,这里就是一个JDK的动态代理,至于不懂JDK代理的同学赶快去学习吧,这个非常的重要。
闲话少扯,我们来看看invoke
方法。前面的几个判断都没有用,在Android平台上根本不会调用,我们直接来看看最后三行代码:
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);
这三行代码,可以被整个Retrofit最核心的代码。表面上来看,只有三行代码,实际上背后给我们做的事情那是数不胜数的。我们来一行一行的看。
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
这行代码的目的是将一个普通的Method
转换成为ServiceMethod
对象。至于怎么转换的话,还有ServiceMethod
是什么,这里先不急着说,我只想说ServiceMethod
是Retrofit
里面非常非常核心的一个类。
我们继续来看第二行代码:
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
这里比较好理解,就是将ServiceMethod
对象包装成为一个OkHttpCall
对象,这个OkHttpCall
对象使用来执行网络请求的。其实它使用了装饰者模式,本身就是一个壳,这个在后面会详细解释。
最后,我们来看看最后一行代码:
return serviceMethod.adapt(okHttpCall);
这里调用了ServiceMethod
的adapt
方法。这里我们可以看看干了吗。
T adapt(Call<R> call) {
return callAdapter.adapt(call);
}
好吧,又调用了callAdapter
的adapt
方法。至于adapt
方法到底干了什么,这不进行展开,后面再讲解CallAdapter
的Factory
时,会详细说到。这里,我们可以这么认为,就是通过调用了callAdapter.adapt
,如果此时的CallAdapter
是RxJava相关的Adapter
,那么这里返回就是Observable<>
之类的。
总之,最后一行代码,就是使用适配器用来适配的。
5. ServiceMethod
现在我们来分析一下这个核心之核心的类。我们还是先从成员变量开始。
static final String PARAM = "[a-zA-Z][a-zA-Z0-9_-]*";
static final Pattern PARAM_URL_REGEX = Pattern.compile("\\{(" + PARAM + ")\\}");
static final Pattern PARAM_NAME_REGEX = Pattern.compile(PARAM);
private final okhttp3.Call.Factory callFactory;
private final CallAdapter<R, T> callAdapter;
private final HttpUrl baseUrl;
private final Converter<ResponseBody, R> responseConverter;
// --------------------
//网络请求相关参数
private final String httpMethod;
private final String relativeUrl;
private final Headers headers;
private final MediaType contentType;
private final boolean hasBody;
private final boolean isFormEncoded;
private final boolean isMultipart;
// --------------------
private final ParameterHandler<?>[] parameterHandlers;
哎呀,这么多我们挑几个重要分析。感觉没什么要分析,callFactory
、callAdapter
、responseConverter
这些在都是Retrofit
里面的含义都是一样的,只不过Retrofit
里面是数组,这里是单个变量,表示从数组选出来的合适的,待会会详细的分析怎么选择。
唯一值得分析的就是parameterHandlers
变量,这个变量是由接口方法的每个参数解析而来的。我们看到,在接口方法里面,每一个参数都会带一些注解,这些信息都是由parameterHandlers
变量来保存,并且可以根据每一个参数的特点,生成特定对象供Request
的构建。这些我们在后面都会详细讲解。
现在,我们可以回去Retrofit的eagerlyValidateMethods
方法和loadServiceMethod
方法。
我们知道,当validateEagerly
变量为true时,会调用eagerlyValidateMethods
方法将接口中的每个方法解析成为ServiceMethod
。我们先来看看:
private void eagerlyValidateMethods(Class<?> service) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
if (!platform.isDefaultMethod(method)) {
loadServiceMethod(method);
}
}
}
eagerlyValidateMethods
方法里面也没有做什么事,具体的操作都在loadServiceMethod
方法里面,我们来看看:
ServiceMethod<?, ?> loadServiceMethod(Method method) {
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
嗯,代码非常的简单,但是代码简单不代表容易理解。我们来具体的分析分析。
首先是判断缓存里面是否有,如果没有的话,就根据条件创建一个ServiceMethod
对象,我们看到ServiceMethod
对象的创建使用的也是建造者模式。我们先来看看ServiceMethod.Builder
的构造方法:
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
相信熟悉Java的同学,这几行代码应该难不倒你们吧?前两句我就不说了,我来解释后三句。
this.methodAnnotations = method.getAnnotations();
这行代码是获取当前方法的注解,比如说,我们在上面的getCall方法添加了@POST
注解和@FormUrlEncoded
注解,这里都可以获得。
this.parameterTypes = method.getGenericParameterTypes();
这个是获取每个参数的类型。
this.parameterAnnotationsArray = method.getParameterAnnotations();
这个是获取每个参数的注解,就比如上面的@Field
。
然后,我们再来看看ServiceMethod.Builder
的build
方法。
public ServiceMethod build() {
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
if (responseType == Response.class || responseType == okhttp3.Response.class) {
throw methodError("'"
+ Utils.getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
responseConverter = createResponseConverter();
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
if (httpMethod == null) {
throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
if (!hasBody) {
if (isMultipart) {
throw methodError(
"Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
}
if (isFormEncoded) {
throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
+ "request body (e.g., @POST).");
}
}
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
if (Utils.hasUnresolvableType(parameterType)) {
throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
parameterType);
}
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
if (parameterAnnotations == null) {
throw parameterError(p, "No Retrofit annotation found.");
}
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
if (relativeUrl == null && !gotUrl) {
throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
}
if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
throw methodError("Non-body HTTP method cannot contain @Body.");
}
if (isFormEncoded && !gotField) {
throw methodError("Form-encoded method must contain at least one @Field.");
}
if (isMultipart && !gotPart) {
throw methodError("Multipart method must contain at least one @Part.");
}
return new ServiceMethod<>(this);
}
build
方法相对来说比较长,这里我将它分为4步:
1. 调用
createCallAdapter
方法,从Retrofit
里面选择合适当前方法的CallAdapter
。
2. 调用createResponseConverter
方法,从Retrofit
里面选择合适当前方法的Convert
。
3.调用parseMethodAnnotation
方法,解析接口方法的注解配置。比如说,上面我们在getCall
方法设置了@POST
和@FormUrlEncoded
注解,在这一步都会被解析出来。
4. 调用parseParameter
方法将方法的每个参数解析成为ParameterHandler
对象。
我们一步一步的分析。首先来看第一步,也就是createCallAdapter
方法的调用。
private CallAdapter<T, R> createCallAdapter() {
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError("Service methods cannot return void.");
}
Annotation[] annotations = method.getAnnotations();
try {
//noinspection unchecked
return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create call adapter for %s", returnType);
}
}
createCallAdapter
表达的意思非常简单,就是根据方法的返回类型和注解类型去Retrofit
里面去寻找合适的CallAdapter
。这里,我们先来看看Retrofit
的callAdapter
方法到底做了什么。
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
callAdapter
方法也是外壳,实际的工作在nextCallAdapter
方法里面做的,我们来看看nextCallAdapter
方法:
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
checkNotNull(returnType, "returnType == null");
checkNotNull(annotations, "annotations == null");
int start = callAdapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
StringBuilder builder = new StringBuilder("Could not locate call adapter for ")
.append(returnType)
.append(".\n");
if (skipPast != null) {
builder.append(" Skipped:");
for (int i = 0; i < start; i++) {
builder.append("\n * ").append(callAdapterFactories.get(i).getClass().getName());
}
builder.append('\n');
}
builder.append(" Tried:");
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
builder.append("\n * ").append(callAdapterFactories.get(i).getClass().getName());
}
throw new IllegalArgumentException(builder.toString());
}
写了那么多,归根结底就是一句话,去寻找合适的CallAdapter,如果找不到的话,就抛出异常。这里我们需要特别的注意一行代码:
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
这里的意思就是去callAdapterFactories
的每个元素寻找合适的CallAdapter
。注意CallAdapter.Factory
的get
方法,后面我们在分析CallAdapter.Factory
会重点的讲解它。
这里先不对CallAdapter.Factory
展开,后面会详细的分析。
以上就是ServiceMethod.Builder
的build方法第一步,也就是寻找合适CallAdapter
。我们现在再来看看第二步。
第二步是调用createResponseConverter
方法,寻找合适的数据转换器。其实跟第一步差不多,我们来简单看看。
createResponseConverter
方法最终会调用到Retrofit
的nextResponseBodyConverter
方法。在nextResponseBodyConverter
方法里面,我们只需要注意一点:
Converter<ResponseBody, ?> converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
这里跟第一步的很像,同样的道理,后面我们在分析数据转换器时会详细的分析它。这里先有一个印象就行。
第三步就是调用parseMethodAnnotation
方法来解析方法的注解,这里所做目的有两点:
- 获取网络请求的配置参数,用以
Request
的构建。- 验证注解是否合法。比如说,在上面的栗子中,使用POST请求,同时还每个参数还有
@Field
注解,所以该方法的注解必须有@FormUrlEncoded
,否则会抛出异常。这些都是Retrofit
的基本规则而已。
最后,我们来看最后一步。最后一步整个4步中最复杂,代码量最多的一步。我们来详细分析分析。
ServiceMethod
通过调用parseParameter
方法将每个参数解析成为ParameterHandler
对象。
而这个ParameterHandler
对象到底是怎么一个东西,接下来我们会通过parseParameter
方法来详细的分析。
通过parseParameter
方法的源码,我们可以看到parseParameter
方法内部还是调用了parseParameterAnnotation
来完成具体的解析工作。由于parseParameterAnnotation
方法太特么的长了,这里我们拿一个特例来分析,就上面栗子中的@Field
注解来分析:
} else if (annotation instanceof Field) {
if (!isFormEncoded) {
throw parameterError(p, "@Field parameters can only be used with form encoding.");
}
Field field = (Field) annotation;
String name = field.value();
boolean encoded = field.encoded();
gotField = true;
Class<?> rawParameterType = Utils.getRawType(type);
if (Iterable.class.isAssignableFrom(rawParameterType)) {
if (!(type instanceof ParameterizedType)) {
throw parameterError(p, rawParameterType.getSimpleName()
+ " must include generic type (e.g., "
+ rawParameterType.getSimpleName()
+ "<String>)");
}
ParameterizedType parameterizedType = (ParameterizedType) type;
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
Converter<?, String> converter =
retrofit.stringConverter(iterableType, annotations);
return new ParameterHandler.Field<>(name, converter, encoded).iterable();
} else if (rawParameterType.isArray()) {
Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
Converter<?, String> converter =
retrofit.stringConverter(arrayComponentType, annotations);
return new ParameterHandler.Field<>(name, converter, encoded).array();
} else {
Converter<?, String> converter =
retrofit.stringConverter(type, annotations);
return new ParameterHandler.Field<>(name, converter, encoded);
}
@Field
注解部分还是那么的多,不过我们不用担心,我们只需要关心最后的三个return部分。为了简单起见,我们先分析最后一个return。
Converter<?, String> converter =
retrofit.stringConverter(type, annotations);
return new ParameterHandler.Field<>(name, converter, encoded);
其中第一句是去Retrofit
里面去寻找合适的StringConverter
。StringConverter
顾名思义,就是将一个对象转换成为String
字符串。就比如说,上面的栗子,我们写的是int
类型,而在网络请求时,提交表单时,这些数据都是String
类型。这个就是StringConverter
的作用。
最后就是创建ParameterHandler.Field
对象。我们先来看看这个类。
static final class Field<T> extends ParameterHandler<T> {
private final String name;
private final Converter<T, String> valueConverter;
private final boolean encoded;
Field(String name, Converter<T, String> valueConverter, boolean encoded) {
this.name = checkNotNull(name, "name == null");
this.valueConverter = valueConverter;
this.encoded = encoded;
}
@Override void apply(RequestBuilder builder, @Nullable T value) throws IOException {
if (value == null) return; // Skip null values.
String fieldValue = valueConverter.convert(value);
if (fieldValue == null) return; // Skip null converted values
builder.addFormField(name, fieldValue, encoded);
}
}
我们在ParameterHandler
时,通常来说只需要关注他的apply
,因为后面ServiceMethod
在构建Request
是通过调用ParameterHandler
的apply
方法来将一个参数转换成为Request
需要的数据。
Field
的apply
方法非常简单,这里就不多说了。
而其他两个return也是比较容易,一个List数组,一个是普通数组,两者都需要遍历来转换,所以一个需要调用iterable
方法,一个需要调用array
方法。这里不对这两个方法做过多的解释,有兴趣的可以看看。
到这里,ServiceMethod
的基本分析也差不多,至于ServiceMethod
怎么将所有的相关信息转换成为一个Resquest
进行网络,怎么调用数据转换器进行数据转换,这些操作在后面我会详细的分析。
接下来,我们来分析平台适配器--CallAdapter
。
6. CallAdapter
大家还记得我们创建Retrofit对象时,通过调用Retrofit.Builder
的addCallAdapterFactory
方法添加了平台适配器的工厂类吗?接下来我们会详细的分析CallAdapter.Factory
,同时还有它的两个子类ExecutorCallAdapterFactory
和RxJava2CallAdapterFactory
。
我们先来看看CallAdapter.Factory
这个抽象类:
abstract class Factory {
/**
* Returns a call adapter for interface methods that return {@code returnType}, or null if it
* cannot be handled by this factory.
*/
public abstract @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,
Retrofit retrofit);
/**
* Extract the upper bound of the generic parameter at {@code index} from {@code type}. For
* example, index 1 of {@code Map<String, ? extends Runnable>} returns {@code Runnable}.
*/
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}
/**
* Extract the raw class type from {@code type}. For example, the type representing
* {@code List<? extends Runnable>} returns {@code List.class}.
*/
protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
这只需要关注get
方法,至于getParameterUpperBound
和getRawType
,我相信大家都非常理解,毕竟注释写的非常清楚。
我们在Retrofit
的nextCallAdapter
方法里面通过调用CallAdapter.Factory
的get
方法来获取合适的CallAdapter
,怎么判断当前的CallAdapter是否合适呢?就是看这个get
方法返回的是否为null。
具体的我们来看看ExecutorCallAdapterFactory
和RxJava2CallAdapterFactory
。我们先来看看那RxJava2CallAdapterFactory
。
(1). RxJava2CallAdapterFactory
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
Class<?> rawType = getRawType(returnType);
if (rawType == Completable.class) {
// Completable is not parameterized (which is what the rest of this method deals with) so it
// can only be created with a single configuration.
return new RxJava2CallAdapter(Void.class, scheduler, isAsync, false, true, false, false,
false, true);
}
boolean isFlowable = rawType == Flowable.class;
boolean isSingle = rawType == Single.class;
boolean isMaybe = rawType == Maybe.class;
if (rawType != Observable.class && !isFlowable && !isSingle && !isMaybe) {
return null;
}
boolean isResult = false;
boolean isBody = false;
Type responseType;
if (!(returnType instanceof ParameterizedType)) {
String name = isFlowable ? "Flowable"
: isSingle ? "Single"
: isMaybe ? "Maybe" : "Observable";
throw new IllegalStateException(name + " return type must be parameterized"
+ " as " + name + "<Foo> or " + name + "<? extends Foo>");
}
Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType);
Class<?> rawObservableType = getRawType(observableType);
if (rawObservableType == Response.class) {
if (!(observableType instanceof ParameterizedType)) {
throw new IllegalStateException("Response must be parameterized"
+ " as Response<Foo> or Response<? extends Foo>");
}
responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
} else if (rawObservableType == Result.class) {
if (!(observableType instanceof ParameterizedType)) {
throw new IllegalStateException("Result must be parameterized"
+ " as Result<Foo> or Result<? extends Foo>");
}
responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
isResult = true;
} else {
responseType = observableType;
isBody = true;
}
return new RxJava2CallAdapter(responseType, scheduler, isAsync, isResult, isBody, isFlowable,
isSingle, isMaybe, false);
}
get
方法前面一系列判断,就是判断当前接口的方法是否支持RxJava适配。怎么才能表示支持RxJava呢?当然是接口方法返回的类型Observable呢。
因为我们可以看到这个判断
if (rawType != Observable.class && !isFlowable && !isSingle && !isMaybe) {
return null;
}
如果返回类型不是Observable
或者Flowable
,这里都会返回null,表示当前的方法不支持RxJava。
如果支持RxJava,最后会返回RxJava2CallAdapter
的对象。我们来看看RxJava2CallAdapter
,我们在分析RxJava2CallAdapter
时,只需要关注adapt
方法即可。
@Override public Object adapt(Call<R> call) {
Observable<Response<R>> responseObservable = isAsync
? new CallEnqueueObservable<>(call)
: new CallExecuteObservable<>(call);
Observable<?> observable;
if (isResult) {
observable = new ResultObservable<>(responseObservable);
} else if (isBody) {
observable = new BodyObservable<>(responseObservable);
} else {
observable = responseObservable;
}
if (scheduler != null) {
observable = observable.subscribeOn(scheduler);
}
if (isFlowable) {
return observable.toFlowable(BackpressureStrategy.LATEST);
}
if (isSingle) {
return observable.singleOrError();
}
if (isMaybe) {
return observable.singleElement();
}
if (isCompletable) {
return observable.ignoreElements();
}
return observable;
}
此时跟Retrofit
的create
方法就串联起来了。在Retrofit
的create
方法里面,最后一行代码就是调用这里的adapt
方法。
在RxJava2CallAdapter
的adapt
方法里面,究竟为我们做了什么?从代码中看来,其实根据情况,给我们创建了一个Observable
对象。
这里,我们还需要注意的是adapt
方法的参数是一个Call
对象,这个Call
对象是什么,用来干嘛的?在Retrofit
的create
方法里面,我们可以知道,这里的Call
对象就是OkHttpCall
对象,这个Call
对象肯定是用来进行网络请求的。这个操作,肯定是在Observable
里面。这里我们来挑一个Observable类看看。注意,接下来的分析都是跟RxJava相关的,如果不懂RxJava原理的同学,肯定感觉很吃力。
这里我们就挑相对难一点的CallEnqueueObservable
来看看。
在看Observable
的源码时,我们需要关注那个方法呢?当然是subscribeActual
方法,因为最终会执行到它来,我们来看看subscribeActual
方法:
@Override protected void subscribeActual(Observer<? super Response<T>> observer) {
// Since Call is a one-shot type, clone it for each new observer.
Call<T> call = originalCall.clone();
CallCallback<T> callback = new CallCallback<>(call, observer);
observer.onSubscribe(callback);
call.enqueue(callback);
}
整个过程的简单,熟悉RxJava和OkHttp的同学肯定感觉非常亲切,最终进行网络请求的就是最后一行代码:
call.enqueue(callback);
由于这里是异步的,所以需要CallBack
对象来进行回调。我们来看看CallBack
的onResponse
方法:
@Override public void onResponse(Call<T> call, Response<T> response) {
// 省略代码
observer.onNext(response);
// 省略代码
}
我们这里就是将网络请求返回的Response
发送给订阅者。
这个就是整个RxJava2CallAdapter
的执行流程。是不是感觉Retrofit
和RxJava
天衣无缝的结合起来了?哈哈,这就是Retrofit
的魅力所在。
至于Call
的enqueue
方法到底做了什么,后面我会详细的分析。
接下来我们看看ExecutorCallAdapterFactory
。相信理解了RxJava2CallAdapterFactory
的工作流程,ExecutorCallAdapterFactory
就不会很难了。
(2). ExecutorCallAdapterFactory
为了少说废话,这里直接看ExecutorCallAdapterFactory
的get
方法:
@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);
}
};
}
在这里,我们发现它只会new了一个CallAdapter
,同时实现了adapt
方法。在adapt
方法里面返回了一个ExecutorCallbackCall
对象。接下来的ExecutorCallbackCall
将Java的静态代理使用的出神入化。
我先来简单的分析整个ExecutorCallbackCall
整个结构。
首先,如果我们在接口定义这个这种类型方法,最终会调用这个的CallAdapter
的adapt
方法:
@POST("getSongPoetry")
@FormUrlEncoded
Call<Bean> getCall(@Field("page") int page, @Field("count") int count);
注意这里返回类型不是Observable
,而是Call
,这里的Call
是什么的对象。我们通过Retrofit
的create
方法获取一个代理对象,代理对象调用getCall
方法,返回的对象在这里,既不是OKHttpCall
,也不是OkHttp
里面的Call
对象,而是这里ExecutorCallbackCall
对象。例如,调用下面的enqueue
方法也是调用ExecutorCallbackCall
的enqueue
方法:
service.getCall(1, 20)
.enqueue(new Callback<Bean>() {
@Override
public void onResponse(Call<Bean> call, Response<Bean> response) {
}
@Override
public void onFailure(Call<Bean> call, Throwable t) {
}
});
而ExecutorCallbackCall
本身就是一个外壳,在ExecutorCallbackCall
的enqueue
方法里面调用了内部的一个代理对象的enqueue
方法。我们来看看:
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}
@Override public void onFailure(Call<T> call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
这个delegate
是什么呢?它就是OkHttpCall
对象。我们发现,在delegate
的Callback
里面使用callbackExecutor
将当前的数据调度到主线程去。
至于为什么调用execute
就会把当前的Response发送到主线程去,这里就不详细的解释了,有兴趣的可以看看Platfrom.Android.MainThreadExecutor
的execute
方法干了什么。
CallAdapter
的部分,我们的分析就到此为止,接下来我们来分析一下OkHttpCall
到底做了什么。
7. 网络执行器--Call
不论是接口返回返回类型为Observable
,而在Observable
的subscribeActual
方法会调用了Call
的enqueue
方法进行网络请求;还是返回类型为Call
,我们直接调用enqueue
方法来进行网络请求。我们都会发现,enqueue
是整个Call
重中之重。
我们先来看看Call
--OkHttpCall
。在Retrofit里面,这里的Call
就是OkHttpCall
。
跟OkHttp里面一样,这里OkHttpCall
也分为同步请求和异步请求,分别对应的是execute
方法和enqueue
方法。我们先来一个一个的来分析。
(1). 同步请求- execute
我们来看看execute
方法的源代码:
@Override public Response<T> execute() throws IOException {
okhttp3.Call call;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
if (creationFailure != null) {
if (creationFailure instanceof IOException) {
throw (IOException) creationFailure;
} else if (creationFailure instanceof RuntimeException) {
throw (RuntimeException) creationFailure;
} else {
throw (Error) creationFailure;
}
}
call = rawCall;
if (call == null) {
try {
call = rawCall = createRawCall();
} catch (IOException | RuntimeException | Error e) {
throwIfFatal(e); // Do not assign a fatal error to creationFailure.
creationFailure = e;
throw e;
}
}
}
if (canceled) {
call.cancel();
}
return parseResponse(call.execute());
}
整个execute方法的过程,我将它分为3步:
1. 创建
rawCall
,也就是OkHttp
里面的call
。
2. 调用rawCall
的execute
方法进行真正的网络请求。
3. 调用parseResponse
方法解析Response。这里面会使用到数据转换器,这个在后面会详细的分析。
还是按着老规矩来,一步一步的来分析。
首先是创建rawCall
对象。这一步最终是调用了ServiceMethod
的toCall
方法。
okhttp3.Call toCall(@Nullable Object... args) throws IOException {
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
contentType, hasBody, isFormEncoded, isMultipart);
@SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
int argumentCount = args != null ? args.length : 0;
if (argumentCount != handlers.length) {
throw new IllegalArgumentException("Argument count (" + argumentCount
+ ") doesn't match expected count (" + handlers.length + ")");
}
for (int p = 0; p < argumentCount; p++) {
handlers[p].apply(requestBuilder, args[p]);
}
return callFactory.newCall(requestBuilder.build());
}
创建rawCall
对象的过程跟OkHttp
里面创建一个Call
是一样的,这里我们只需关注下面的代码就行了。
for (int p = 0; p < argumentCount; p++) {
handlers[p].apply(requestBuilder, args[p]);
}
这里调用ParameterHandler
的apply
方法将每个参数转换成为网络请求真正需要的数据,这里与前面我们分析parseParameter
方法不谋而合。
创建好了rawCall
对象,此时就应该调用rawCall
的execute
方法来进行网络请求。这里的原理就是OkHttp
的知识,这里就不在展开了,有兴趣的同学,可以参考我的OkHttp
源码分析系列-OkHttp 源码分析系列。
最后就是调用parseResponse
方法来进行数据转化。我们来简单看看parseResponse
方法
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
// Remove the body's source (the only stateful object) so we can pass the response along.
rawResponse = rawResponse.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
int code = rawResponse.code();
if (code < 200 || code >= 300) {
try {
// Buffer the entire body to avoid future I/O.
ResponseBody bufferedBody = Utils.buffer(rawBody);
return Response.error(bufferedBody, rawResponse);
} finally {
rawBody.close();
}
}
if (code == 204 || code == 205) {
rawBody.close();
return Response.success(null, rawResponse);
}
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
T body = serviceMethod.toResponse(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
// If the underlying source threw an exception, propagate that rather than indicating it was
// a runtime exception.
catchingBody.throwIfCaught();
throw e;
}
}
在parseResponse
方法里面有很多的判断,这里我们不需要有太多的关注,只需要看下面这一行代码就行了:
T body = serviceMethod.toResponse(catchingBody);
通过调用ServiceMethod
的toResponse
方法将RequestBody
转换成为我们需要的Bean对象。我们来看看ServiceMethod
的toResponse
方法。
R toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
}
这里没有过多的操作,只是简单调用Converter
的convert
方法来进行数据转换。这里先不对Converter
做过多的解释,待会会详细的分析它。
整个三步执行完了,就是OKHttpCall
的execute
执行完毕。不得不说Retrofit的代码设计是多么的优秀,整个过程酣畅淋漓,一切都感觉合情合理的。
接下里,我们来看看异步请求的过程。
(2). 异步请求- enqueue
异步请求跟同步请求比较起来,只是多了一个Callback
参数。而这个Callback就是我们在调用enqueue
方法传入的Callback
,这里就不对enqueue
做过多的解释了。
接下来,我们分析一下Retrofit最后一个部分Converter
--数据转换器
8.数据转换器--Converter
在创建Retrofit对象时,我们通过调用Retrofit.Builder
的addConverterFactory
添加了一个数据转换器。我们来看看代码:
private Retrofit mRetrofit = new Retrofit.Builder()
.baseUrl("http://api.apiopen.top/")
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
我们直接来看看Converter.Factory
这个类:
abstract class Factory {
/**
* Returns a {@link Converter} for converting an HTTP response body to {@code type}, or null if
* {@code type} cannot be handled by this factory. This is used to create converters for
* response types such as {@code SimpleResponse} from a {@code Call<SimpleResponse>}
* declaration.
*/
public @Nullable Converter<ResponseBody, ?> responseBodyConverter(Type type,
Annotation[] annotations, Retrofit retrofit) {
return null;
}
/**
* Returns a {@link Converter} for converting {@code type} to an HTTP request body, or null if
* {@code type} cannot be handled by this factory. This is used to create converters for types
* specified by {@link Body @Body}, {@link Part @Part}, and {@link PartMap @PartMap}
* values.
*/
public @Nullable Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
return null;
}
/**
* Returns a {@link Converter} for converting {@code type} to a {@link String}, or null if
* {@code type} cannot be handled by this factory. This is used to create converters for types
* specified by {@link Field @Field}, {@link FieldMap @FieldMap} values,
* {@link Header @Header}, {@link HeaderMap @HeaderMap}, {@link Path @Path},
* {@link Query @Query}, and {@link QueryMap @QueryMap} values.
*/
public @Nullable Converter<?, String> stringConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return null;
}
/**
* Extract the upper bound of the generic parameter at {@code index} from {@code type}. For
* example, index 1 of {@code Map<String, ? extends Runnable>} returns {@code Runnable}.
*/
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}
/**
* Extract the raw class type from {@code type}. For example, the type representing
* {@code List<? extends Runnable>} returns {@code List.class}.
*/
protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
这里需要重点关注三个方法,一个是responseBodyConverter
,另一个方法是requestBodyConverter
,还有一个是stringConverter
。前两个方法我们从名字上就可以知道是什么意思,一个将获取Response
的转换器;一个是获取Request
的转换器;stringConverter
方法,我们在将每个参数解析成为ParameterHandler
对象看到过,这个方法的作用主要将参数转换成为网络请求需要的配置参数。
具体的实现,我们来看GsonConverterFactory
,在这里,我们重点分析一下responseBodyConverter
方法,requestBodyConverter
方法跟responseBodyConverter
是一样的原理。
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonResponseBodyConverter<>(gson, adapter);
}
这里创建了一个GsonResponseBodyConverter
对象,我们来看看这个类:
final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
private final Gson gson;
private final TypeAdapter<T> adapter;
GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
this.gson = gson;
this.adapter = adapter;
}
@Override public T convert(ResponseBody value) throws IOException {
JsonReader jsonReader = gson.newJsonReader(value.charStream());
try {
T result = adapter.read(jsonReader);
if (jsonReader.peek() != JsonToken.END_DOCUMENT) {
throw new JsonIOException("JSON document was not fully consumed.");
}
return result;
} finally {
value.close();
}
}
}
整个GsonResponseBodyConverter
非常的简单,在ServiceMethod
的toResponse
方法里面,就是调用了convert
方法将Response
的body
转换成为我们的Bean
对象。
而我们从这里可以看出来,整个convert
方法非常的简单,没有做什么难以理解的操作,实际上,所有的解析工作都是由Gson给我们完成的。从这里来看,Gson确实强大,不愧是Google爸爸的东西。这里就不对Gson做过多的解释,因为我也不懂😂。
9. 总结
最后,我们对Retrofit做一个简单的总结。
1. Retrofit大体上分为4个部分:接口、
Request
(ServiceMethod
)、网络请求执行器Call
、数据转换器Converter
。每个部分都有自己的职责。
2.Retrofit
里面最核心的一个类就是ServiceMethod
。这个类负责解析方法,生成对应的Request
,转换Response。
3. Retrofit 内部使用太多太多的设计模式,是学习设计模式的不二典范。