前言
Retrofit 是现在 Android 主流的网络请求库,对比 Volley 它解耦更加彻底,使用更加方便,而且支持 RxJava。具体的区别的可以看看这篇文章——OkHttp, Retrofit, Volley应该选择哪一个?。
Retrofit 中文可以翻译成 在原有基础上改进。它的底层基于 OkHttp。
Retrofit 的精简流程图,图片来自Stay:

Retrofit 中使用了大量设计模式,分析源码之前最好先熟悉一下这些模式。
- 建造者模式
- 工厂模式
- 外观模式
- 策略模式
- 适配器模式
- 装饰模式
- 代理模式及 Java 动态代理
还涉及一些基础的 Java 注解的知识,建议先打好基础再分析源码。
Retrofit的类的结构

上层有4个抽象接口,有默认的实现类。核心服务类是ServiceMethod。Platform判断Android,Java平台。
Call
/**
* 这是一个Retrofit方法给服务器发送一个request,返回一个response的调用。
* 每个Call生产一组HTTP request和response。对于同一个完全一样请求,实现
* clone方法来创建多个call,这个可以用于轮询和错误重试的场景。
*
* Calls 同步执行的时候使用 execute(), 异步执行使用 enqueue()。无论是
* 同步还是异步都可以在请求的时候使用 cancel() 随时被取消。正在写入request或者读取response的Call可能会引起IOException。
*
*
* @param <T> 请求成功时返回的 response body 类型
*/
public interface Call<T> extends Cloneable {
// 同步发起请求返回response
Response<T> execute() throws IOException;
// 异步发起请求,结果返回给回调
void enqueue(Callback<T> callback);
// 如果call已经调用了execute()或者enqueue()就返回true。不允许一个call重复请求。
boolean isExecuted();
// 取消正在执行中的请求,如果call还没开始执行请求,就不做任何处理。
void cancel();
// 是否取消了请求
boolean isCanceled();
// 创建一个新的和当前完全一样的call
Call<T> clone();
// 原始的HTTP请求
Request request();
}
CallAdapter
用于RxJava的转化。
public interface CallAdapter<R, T> {
// 返回解析成java对象的response的类型。
Type responseType();
T adapt(Call<R> call);
// 抽象工厂类
abstract class Factory {
public abstract CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,
Retrofit retrofit);
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}
protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
}
Callback
public interface Callback<T> {
void onResponse(Call<T> call, Response<T> response);
void onFailure(Call<T> call, Throwable t);
}
Converter
public interface Converter<F, T> {
// 实体类和HTTP的RequestBody和ResponseBody的互相转换
T convert(F value) throws IOException;
// 抽象工厂
abstract class Factory {
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return null;
}
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
return null;
}
public Converter<?, String> stringConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return null;
}
}
}
正常请求网络的套路

- build request 参数,加入到请求队列中
- 在子线程轮询执行
- 得到服务器数据后,回调给上层
Retrofit 不外乎也是这种套路,那么它到底有什么精妙的地方呢?
举个栗子
先看一个正常 Retrofit 请求的例子:
Retrofit build = new Retrofit.Builder().baseUrl(ServiceApi.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
ServiceApi serviceApi = build.create(ServiceApi.class);
serviceApi.getHistoryDate().enqueue(new Callback<String>() {
@Override public void onResponse(Call<String> call, Response<String> response) {
Log.d(TAG, "onResponse- " + response.body());
}
@Override public void onFailure(Call<String> call, Throwable t) {
Log.d(TAG, "onFailure- " + t.getMessage());
}
});
/**
* API 来自 gank.io,感谢 @代码家
*/
interface ServiceApi {
String BASE_URL = "http://gank.io/api/";
/**
* 获取某一天的数据
*/
@GET("day/{year}/{month}/{day}") Call<String> getDataOnSomeday(
@Path("year") String year, @Path("month") String month, @Path("day") String day);
}
我们通过调用 serviceApi.getHistoryDate().enqueue(callback) 请求数据并在回调中处理数据。
就从这行代码作为切入点,看看发出请求的时候到底内部发生了啥?
debug serviceApi.getHistoryDate() 这行代码我发现,运行至此的时候调用了动态代理,代码走到了下面的 create(final Class<T> service) 中的 InvocationHandler() 中,回调了 invoke()。

我们来仔细分析一下这个函数。
/**
* 创建由 service 定义的 API 的实现。
* return 类型还是为 T 的代理对象
*/
public <T> T create(final Class<T> service) {
// 检查 service 是否合法,必须是接口且只有 1 个接口,
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, 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 serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
很明显这是一个 Java 动态代理。这个方法在 ServiceApi serviceApi = build.create(ServiceApi.class); 调用,返回的是一个代理对象。
在invoke(Object proxy, Method method, Object... args)中,Retrofit 只关心 method 和 args 两个参数。
核心代码是这 3 句:
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
ServcieMethod
ServiceMethod就像是一个中央处理器,传入Retrofit对象和Method对象,调用各个接口和解析器,最终生成一个Request,包含api 的域名、path、http请求方法、请求头、是否有body、是否是multipart等等。最后返回一个Call对象,Retrofit2中Call接口的默认实现是OkHttpCall,它默认使用OkHttp3作为底层http请求client。
使用Java动态代理的目的就要拦截被调用的Java方法,然后解析这个Java方法的注解,最后生成Request由OkHttp发送。
先看 loadServiceMethod(method),从这里面得到一个 ServiceMethod
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result;
synchronized (serviceMethodCache) {
// 先从缓存中取
result = serviceMethodCache.get(method);
if (result == null) {
// 如果没有就新建,然后加入缓存
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
build方法里面创建了CallAdapter和Converter。处理注解,将其转化成OkHttp Call。
/**
* 创建 CallAdapter,创建 Converter,解析注释
* ServiceMethod 的作用是将接口方法的调用适配为 HTTP Call
* return ServiceMethod 对象
*/
public ServiceMethod build() {
// 创建callAdapter
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
// 创建Converter
responseConverter = createResponseConverter();
// 遍历,解析方法注释
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
// 参数里的注解的个数
int parameterCount = parameterAnnotationsArray.length;
// 创建对应的 parameterHandlers数组。将每个参数的注解解析成parameterHandler对象存入数组。
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
return new ServiceMethod<>(this);
}
这里的parameterHandlers 负责解析API定义时每个方法的参数,并在构造HTTP请求时设置参数。
解析方法注释
private void parseMethodAnnotation(Annotation annotation) {
if (annotation instanceof DELETE) {
parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
} else if (annotation instanceof GET) {
parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
}
// ...省略代码
}
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
this.httpMethod = httpMethod;
this.hasBody = hasBody;
if (value.isEmpty()) {
return;
}
// Get the relative URL path and existing query string, if present.
int question = value.indexOf('?');
if (question != -1 && question < value.length() - 1) {
// Ensure the query string does not have any named parameters.
String queryParams = value.substring(question + 1);
Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams);
}
this.relativeUrl = value;
this.relativeUrlParamNames = parsePathParameters(value);
}
static Set<String> parsePathParameters(String path) {
Matcher m = PARAM_URL_REGEX.matcher(path);
Set<String> patterns = new LinkedHashSet<>();
while (m.find()) {
patterns.add(m.group(1));
}
return patterns;
}
parameterHandlers
每个参数都会有一个 ParameterHandler,由 ServiceMethod#parseParameter 方法负责创建,其主要内容就是解析每个参数使用的注解类型(诸如 Path,Query,Field 等),对每种类型进行单独的处理。构造 HTTP 请求时,我们传递的参数都是字符串,那 Retrofit 是如何把我们传递的各种参数都转化为 String 的呢?还是由 Retrofit 类提供 converter!
Converter.Factory 除了提供上一小节提到的 responseBodyConverter,还提供 requestBodyConverter 和 stringConverter,API 方法中除了 @Body 和 @Part 类型的参数,都利用 stringConverter 进行转换,而 @Body 和 @Part 类型的参数则利用 requestBodyConverter 进行转换。
CallAdapter
// #ServiceMethod.java
this.callFactory = builder.retrofit.callFactory();
CallAdapter由retrofit提供,我们可以自己指定,默认是okhttp3.OkHttpClient。
创建callAdapter由retrofit完成。
private CallAdapter<T, R> createCallAdapter() {
return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
}
// # Retrofit.java
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
最终走到nextCallAdapter(),通过CallAdapter.Factory来创造。
public CallAdapter<?, ?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
// ...省略多若干码
// 去除skipPast这个过去的工厂,Retrofit默认传的是null。
int start = adapterFactories.indexOf(skipPast) + 1;
// 遍历取出第一个工厂,获得adapter。
for (int i = start, count = adapterFactories.size(); i < count; i++) {
CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
}
ResponseConverter
和callAdapter一样,也是由Retrofit创建的。通过遍历 Converter.Factory 列表,看看有没有工厂能够提供需要的 responseBodyConverter。工厂列表同样可以在构造 Retrofit 对象时进行添加。
OkHttpCall
OkHttpCall实现了Call接口。
okHttpCall 关键的部分是:
private okhttp3.Call createRawCall() throws IOException {
Request request = serviceMethod.toRequest(args);
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
// ServiceMethod.java # toRequest()
/** Builds an HTTP request from method arguments. */
Request toRequest(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;
// 省略部分检查代码
for (int p = 0; p < argumentCount; p++) {
handlers[p].apply(requestBuilder, args[p]);
}
return requestBuilder.build();
}
这里由serviceMethod创建request,之前的ParameterHandler这里就用到了,这里把参数传进去一起组成完整request。并且由serviceMethod里的callFactory创建一个Call,默认就是OkHttpCall。
调用execute()执行同步请求:
@Override public Response<T> execute() throws IOException {
okhttp3.Call call;
// 省略判断代码...
call = rawCall = createRawCall();
// 省略判断代码...
// 最终调用 parseResponse 解析返回的结果
return parseResponse(call.execute());
}
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 {
// 这里调用serviceMethod中的方法用对应的ConvertFactory转换
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;
}
}