文章使用的Retrofit版本为:2.3.0
在前面的文章已经介绍过了Retrofit的使用,这篇文章主要是分析Retrofit的源码。
源码解析
首先我们从Retrofit的初始化配置开始说起:
Retrofit retrofit = new Retrofit.Builder()
.client(new OkHttpClient.Builder().build())
.baseUrl("http://www.baidu.com/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
这是我们常见的Retrofit初始化的代码,从 Builder()
、.build()
就能明白Retrofit和okhttp一样是使用建造者模式来构建对象的,看源码我们先看这个类的成员变量,好的代码规范从命名我们就能初步理解这个类大概是做哪些事:
public static final class Builder {
private final Platform platform; // 运行的平台,Retrofit可以运行在ios、Android、Java3个平台环境下,会根据当前环境去适配不同的平台
@Nullable
private Factory callFactory;// Okhttp的工厂类
private HttpUrl baseUrl;// baseUrl,HttpUrl类型
private final List<retrofit2.Converter.Factory> converterFactories; // 数据转换器的集合,主要作用是将网络请求返回的数据转换成用户想要的格式,用户可自定义解析方式,比如Gson、FastJson
private final List<retrofit2.CallAdapter.Factory> adapterFactories; // 数据适配器的集合,主要作用是将接口返回的对象适配成用户想要的对象,用户可自定义,比如RxJava
@Nullable
private Executor callbackExecutor;// 回调执行器,网络请求返回数据通过这个进行回调
private boolean validateEagerly;// 是否提前解析注解等信息
//省略其余代码...
}
代码中的注释是我自己加上去的,注释很详细,这里就不多解释了。
我们跟着 .build()
方法进去看源码:
public Retrofit build() {
if (this.baseUrl == null) {
throw new IllegalStateException("Base URL required.");
} else {
Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = this.platform.defaultCallbackExecutor();
}
List<retrofit2.CallAdapter.Factory> adapterFactories = new ArrayList(this.adapterFactories);
adapterFactories.add(this.platform.defaultCallAdapterFactory(callbackExecutor));
List<retrofit2.Converter.Factory> converterFactories = new ArrayList(this.converterFactories);
return new Retrofit((Factory)callFactory, this.baseUrl, converterFactories, adapterFactories, callbackExecutor, this.validateEagerly);
}
}
build()
方法中首先就判断了baseUrl是否为空,如果为空会抛出一个异常提示 Base URL required.
这也是为什么在 Retrofit 2.x 系列之一 - Retrofit的使用姿势(基础篇) 这篇文章中说 baseUrl()
为必需项了。
当baseUrl不为空时,走到else的代码分支,判断 this.callFactory
是否为空,如果为空则初始化一个默认的 OkhttpClient
对象,同样也验证了基础篇文章中说的 client()
为可选项,这一步我们先停下来看 this.callFactory
在哪里被赋值的:
public Retrofit.Builder client(OkHttpClient client) {
return this.callFactory((Factory)Utils.checkNotNull(client, "client == null"));
}
public Retrofit.Builder callFactory(Factory factory) {
this.callFactory = (Factory)Utils.checkNotNull(factory, "factory == null");
return this;
}
通过 Builder().client()
方法传入 OkhttpClient
实例,紧接着调用自己的 callFactory()
方法,在该方法内部对 callFactory
这个成员变量赋值。我们回到 build()
方法继续看。
判断完 callFactory
之后,判断 callbackExecutor
,这个变量我们一般都不会去配置它,所以这里默认为null,Retrofit就会使用各自平台的 defaultCallbackExecutor
。因为我们是 Android
中使用,我们去看Android平台默认的 callbackExecutor
是什么:
static class Android extends Platform {
Android() {
}
public Executor defaultCallbackExecutor() {
return new Platform.Android.MainThreadExecutor();
}
Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
if (callbackExecutor == null) {
throw new AssertionError();
} else {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
MainThreadExecutor() {
}
public void execute(Runnable r) {
this.handler.post(r);
}
}
}
代码中可以看到无参的 defaultCallbackExecutor()
方法中返回的是 MainThreadExecutor
,也就是将返回接口切换到主线程中执行。
最后 build()
方法创建了 adapterFactories
、converterFactories
的集合,并将我们添加进去的数据转换器(本文中为 GsonConverterFactory
)、数据适配器(本文中为 RxJavaCallAdapterFactory
)传入集合,然后使用配置好的所有参数构建了Retrofit对象。至此Retrofit就创建好了。
初始化配置完成后,第二步就是与网络请求的接口类配合,创建能够发起网络请求的对象。但是在Retrofit的使用步骤中,我们是创建了一个接口来配置网络请求的方式、参数、Header等等,接口是不能实例化的,所以,Retrofit使用了动态代理
的方式(非常重要),动态代理的相关知识可以看:你真的完全了解Java动态代理吗?看这篇就够了 这篇文章,里面描述了动态代理的使用场景、设计思想和原理。我们看一下Retrofit是如何使用动态代理的:
Api api = retrofit.create(Api.class);
我们跟着 create()
方法进入源码:
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (this.validateEagerly) {
this.eagerlyValidateMethods(service);
}
return Proxy.newProxyInstance(service.getClassLoader(), new Class[]{service}, new InvocationHandler() {
private final Platform platform = Platform.get();
public Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
} else if (this.platform.isDefaultMethod(method)) {
return this.platform.invokeDefaultMethod(method, service, proxy, args);
} else {
ServiceMethod<Object, Object> serviceMethod = Retrofit.this.loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
}
});
}
create()
方法中第一步先验证一下传递进来的接口类的合法性,第二步判断是否要提前解析接口类中的方法,第三步就是创建动态代理了。这里的动态代理会将我们编写的请求接口类中所有方法,都委托到这个动态代理去处理,每当我们调用一个方法,动态代理中 InvocationHandler
对象的 invoke
方法就会执行一次。 invoke
方法中前两个 if
代码块中都是别的平台(ios、java8),我们只要关注最后的 else
代码块,里面的三行代码就是Retrofit最重要的地方了,我们跟着第一个方法 loadServiceMethod
进去看:
ServiceMethod<?, ?> loadServiceMethod(Method method) {
ServiceMethod<?, ?> result = (ServiceMethod)this.serviceMethodCache.get(method);
if (result != null) {
return result;
} else {
Map var3 = this.serviceMethodCache;
synchronized(this.serviceMethodCache) {
result = (ServiceMethod)this.serviceMethodCache.get(method);
if (result == null) {
result = (new retrofit2.ServiceMethod.Builder(this, method)).build();
this.serviceMethodCache.put(method, result);
}
return result;
}
}
}
该方法会先从缓存中获取 ServiceMethod
对象,如果获取不到就利用 Builder
创建一个,再加入缓存。我们看看 ServiceMethod.Builder
对象是什么,因为 Builder
是用来创建 ServiceMethod
的,知道了 Builder
就能知道 ServiceMethod
,和查看 Retrofit
类一样,先看下成员变量都有什么:
static final class Builder<T, R> {
final Retrofit retrofit;
final Method method;
final Annotation[] methodAnnotations; // 方法的注解:@Post、@Header 等等
final Annotation[][] parameterAnnotationsArray; // 方法中参数的注解:@Field、@Query 等等
final Type[] parameterTypes; //参数类型
Type responseType; //返回类型
boolean gotField;
boolean gotPart;
boolean gotBody;
boolean gotPath;
boolean gotQuery;
boolean gotUrl;
String httpMethod; // 请求方法
boolean hasBody; // 是否有请求体
boolean isFormEncoded; // 是否是表单
boolean isMultipart; // 是否是文件
String relativeUrl;
Headers headers; // 请求头
MediaType contentType; // 媒体类型
Set<String> relativeUrlParamNames;
ParameterHandler<?>[] parameterHandlers; // 根据请求方法将参数中的注解处理成网络请求的请求体内容
Converter<ResponseBody, T> responseConverter; //返回数据的转换器
CallAdapter<T, R> callAdapter; // 方法返回值得对象适配器
//省略其余代码...
}
代码中添加了注释,通过注释我们能知道,这个 ServiceMethod
类就是对我们自定义的 ApiService接口
中的所有注解、方法、参数逐一去进行解析,解析的步骤在该类的 build()
方法中:
public ServiceMethod build() {
this.callAdapter = this.createCallAdapter();
this.responseType = this.callAdapter.responseType();
if (this.responseType != Response.class && this.responseType != okhttp3.Response.class) {
this.responseConverter = this.createResponseConverter();
Annotation[] var1 = this.methodAnnotations;
int p = var1.length;
for(int var3 = 0; var3 < p; ++var3) {
Annotation annotation = var1[var3];
this.parseMethodAnnotation(annotation);
}
if (this.httpMethod == null) {
throw this.methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
} else {
if (!this.hasBody) {
if (this.isMultipart) {
throw this.methodError("Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
}
if (this.isFormEncoded) {
throw this.methodError("FormUrlEncoded can only be specified on HTTP methods with request body (e.g., @POST).");
}
}
int parameterCount = this.parameterAnnotationsArray.length;
this.parameterHandlers = new ParameterHandler[parameterCount];
for(p = 0; p < parameterCount; ++p) {
Type parameterType = this.parameterTypes[p];
if (Utils.hasUnresolvableType(parameterType)) {
throw this.parameterError(p, "Parameter type must not include a type variable or wildcard: %s", parameterType);
}
Annotation[] parameterAnnotations = this.parameterAnnotationsArray[p];
if (parameterAnnotations == null) {
throw this.parameterError(p, "No Retrofit annotation found.");
}
this.parameterHandlers[p] = this.parseParameter(p, parameterType, parameterAnnotations);
}
if (this.relativeUrl == null && !this.gotUrl) {
throw this.methodError("Missing either @%s URL or @Url parameter.", this.httpMethod);
} else if (!this.isFormEncoded && !this.isMultipart && !this.hasBody && this.gotBody) {
throw this.methodError("Non-body HTTP method cannot contain @Body.");
} else if (this.isFormEncoded && !this.gotField) {
throw this.methodError("Form-encoded method must contain at least one @Field.");
} else if (this.isMultipart && !this.gotPart) {
throw this.methodError("Multipart method must contain at least one @Part.");
} else {
return new ServiceMethod(this);
}
}
} else {
throw this.methodError("'" + Utils.getRawType(this.responseType).getName() + "' is not a valid response body type. Did you mean ResponseBody?");
}
}
第一个for循环中的 this.parseMethodAnnotation(annotation);
主要是对请求方法(@GET、@POST、@DELETE等等)进行解析。
然后我们回到创建动态代理的 invoke()
方法源码中:
ServiceMethod<Object, Object> serviceMethod = Retrofit.this.loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
通过 loadServiceMethod()
方法已经创建好 ServiceMethod
,而 ServiceMethod
类中也保存了解析后的请求所需的各种相关信息,紧接着创建了 OkHttpCall
对象,这个对象是 Retrofit
中对 OkHttp
的 Call
接口的实现类,当我们调用 异步请求 enqueue
或者 同步请求 execute
时,就是通过 OkHttpCall
去调用 OkHttp
的请求,所以我们说 Retrofit
和其他 OkHttpUtils
的开源项目一样,只是对 OkHttp
的一种封装,底层的网络请求还是通过 OkHttp
发起的。由于篇幅过长, OkHttpCall
源码相对简单,我们这里就不展开对它的源码解析了,感兴趣的道友可自行查看。
回到主题,我们接着看最后一行代码,调用了 serviceMethod.callAdapter.adapt(okHttpCall);
,这里就是为什么我们通过添加 RxJavaCallAdapterFactory
之后,我们可以在请求结果返回 RxJava
的对象了。
到这里我们还存在一个疑问,RxJavaCallAdapterFactory
的工作时机我们看到了,那 GsonConverterFactory
呢?
这就要说回 OkhttpCall
了,假设我们执行的是 异步请求 enqueue
,在其内部最终会调用 OkHttp
的 call
的 enqueue
方法:
call.enqueue(new okhttp3.Callback() {
public void onResponse(okhttp3.Call call, Response rawResponse) throws IOException {
retrofit2.Response response;
try {
response = OkHttpCall.this.parseResponse(rawResponse);
} catch (Throwable var5) {
this.callFailure(var5);
return;
}
this.callSuccess(response);
}
//省略其他代码...
});
在结果的回调中,调用了自己的 parseResponse
方法:
retrofit2.Response<T> parseResponse(Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
rawResponse = rawResponse.newBuilder().body(new OkHttpCall.NoContentResponseBody(rawBody.contentType(), rawBody.contentLength())).build();
int code = rawResponse.code();
if (code >= 200 && code < 300) {
if (code != 204 && code != 205) {
OkHttpCall.ExceptionCatchingRequestBody catchingBody = new OkHttpCall.ExceptionCatchingRequestBody(rawBody);
try {
T body = this.serviceMethod.toResponse(catchingBody);
return retrofit2.Response.success(body, rawResponse);
} catch (RuntimeException var9) {
catchingBody.throwIfCaught();
throw var9;
}
} else {
rawBody.close();
return retrofit2.Response.success((Object)null, rawResponse);
}
} else {
retrofit2.Response var5;
try {
ResponseBody bufferedBody = Utils.buffer(rawBody);
var5 = retrofit2.Response.error(bufferedBody, rawResponse);
} finally {
rawBody.close();
}
return var5;
}
}
在一个try catch代码块中,调用了 this.serviceMethod.toResponse(catchingBody);
这里就是去找到我们创建 Retrofit
时传递进去的 ConverterFactory
把网络请求返回的数据转换成我们自己想要的格式。
至此,整个 Retrofit
的源码就解析完了,在整个过程中我们会发现 Retrofit
将设计模式充分运用在了整个项目中,比如:Builder模式(建造者模式)、适配器模式(Adapter)、工厂模式(Factory)、代理模式(Procy)、装饰模式(OkHttpCall)等等,这也让我意识到设计模式能够给我们的架构带来质的飞跃,因此还需要多看源码,才能不断进步。