原载于个人博客Retrofit源码探秘, 转载请注明出处, 谢谢.
本文讲Retrofit. 总的来说它是一个面向业务流程的网络请求库, 内部默认使用面向网络协议的库OkHttp来打出成吨伤害.
截至我写文章为止, Retrofit更新到了2.2.0版本. 据说1.x与2.0+差异巨大, 这里我们就直接拥抱变化来看最新代码了.
Retrofit的使用
添加依赖和添加网络权限我就不说了. 假设我们要访问网络获取一个Json格式的响应, 来看代码怎么写:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://url.of.yourserver/")
.addConverterFactory(GsonConverterFactory.create())
.build(); // 创建全局管理
HttpService httpService = retrofit.create(YourHttpService.class); // 创建访问接口实例
Call<Json> call = httpService.getJson(); // 为要访问的接口创建Call
call.enqueue(new YourCallbackForThisCall(){...}); // Call入队列并添加回调
非常简单对不对, 而且YourHttpService.class甚至可能根据某种规范直接从服务端导出, 需要自己手写的代码几乎可以忽略不计, 出bug的几率就更小了.
这里的Callback经我验证是在UI线程执行的, 所以可以直接在onResponse里更新UI. 如果想要换到其他线程处理, 需要设置callbackExecutor, 默认是主线程.
Retrofit源码探秘
根据我们前面分析过的OkHttp源码可以知道, Retrofit背后的请求发送和接收都是通过它来完成的, 自己几乎没做什么. Retrofit能实现这么简单的调用方式, 其魔法就在它的抽象架构上. Retrofit通过定义和解析注解的方式生成Request, 又在原本OkHttpCall(Retrofit定义的OkHttp的代理)的回调之中加了一层, 用于处理响应出错情况和把响应结果包装成ExceptionCatchingRequestBody, 最后用ServiceMethod.toResponse使用Converter完成响应解析, 使用解析结果通过CallAdapter构造一个自定义的Response<T>并返回. 再在外层回调我们设置的Callback<T>.
真正的网络请求的事情包括连接和缓存的维护都交给OkHttpClient完成了, 因此关键就在于Retrofit从注解到Call的过程和从Response到Response<T>的过程.
Retrofit注解定义和解析
在我之前的某篇文章中曾经解析过Java的Annotation机制, 这里就不再解释了, 我们已经知道, Java的注解是通过注解处理器Processor进行处理的, Retrofit应该也是实现了类似的机制去处理它自己的注解. 注解都是编译器完成处理的, 其处理后的代码的生命周期根据它的Retention不同而不同, Retention为RUNTIME的注解在编译器处理之后存在于.class文件中并且还被虚拟机载入, 所以可供后续处理. 接下来我们就来看看Retrofit中的注解定义和解析器的定义, 我们将会发现它所有的注解都是RUNTIME的.
注解都在http包下, 从名字也看得出来基本上对应了http协议中的各个实体. 我们只看其中GET Headers Streaming三个.
选这三个的原因是三个在http协议中分别代表三种类型: 请求方法, 结构参数, 传输标记. 如果不记得http协议的同学可以看我另一篇博客Android源码解析-网络架构.
三个注解的完整代码如下:
@Target(METHOD)
@Retention(RUNTIME)
public @interface GET {
/**
* A relative or absolute path, or full URL of the endpoint. This value is optional if the first
* parameter of the method is annotated with {@link Url @Url}.
* <p>
* See {@linkplain retrofit2.Retrofit.Builder#baseUrl(HttpUrl) base URL} for details of how
* this is resolved against a base URL to create the full endpoint URL.
*/
String value() default "";
}
/**
* Adds headers literally supplied in the {@code value}.
* <pre><code>
* @Headers("Cache-Control: max-age=640000")
* @GET("/")
* ...
*
* @Headers({
* "X-Foo: Bar",
* "X-Ping: Pong"
* })
* @GET("/")
* ...
* </code></pre>
* <strong>Note:</strong> Headers do not overwrite each other. All headers with the same name will
* be included in the request.
*
* @see Header
* @see HeaderMap
*/
@Documented
@Target(METHOD)
@Retention(RUNTIME)
public @interface Headers {
String[] value();
}
/**
* Treat the response body on methods returning {@link okhttp3.Response Response} as is,
* i.e. without converting {@link okhttp3.Response#body() body()} to {@code byte[]}.
*/
@Documented
@Target(METHOD)
@Retention(RUNTIME)
public @interface Streaming {
}
为避免各位说我凑篇幅, 请各位仔细看上文代码的注释部分和注解部分, 我们可以看到这几个注解的设计思路, 基本上是按照http协议的基本部分来分解的, 并且都有明确的作用对象和作用范围.
对这三种类型的注解的处理自然也是不太一样, 接下来我们就看看Retrofit为它的这些注解编写了怎样的处理器. 注解的转存在ServiceMethod.Builder()中, 处理则在ServiceMethod.Builder.build()中, 如下:
public ServiceMethod build() {
...
// Method级别的Annotation, 主要是GET/POST等方法
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
...
// Parameter级别的Annotation, 主要是Path等
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);
}
...
}
// 处理Method级别Annotation
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);
} else if (annotation instanceof HEAD) {
parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
if (!Void.class.equals(responseType)) {
throw methodError("HEAD method must use Void as response type.");
}
} else if (annotation instanceof PATCH) {
parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
} else if (annotation instanceof POST) {
parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
} else if (annotation instanceof PUT) {
parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
} else if (annotation instanceof OPTIONS) {
parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
} else if (annotation instanceof HTTP) {
HTTP http = (HTTP) annotation;
parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
} else if (annotation instanceof retrofit2.http.Headers) {
String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
if (headersToParse.length == 0) {
throw methodError("@Headers annotation is empty.");
}
headers = parseHeaders(headersToParse);
} else if (annotation instanceof Multipart) {
if (isFormEncoded) {
throw methodError("Only one encoding annotation is allowed.");
}
isMultipart = true;
} else if (annotation instanceof FormUrlEncoded) {
if (isMultipart) {
throw methodError("Only one encoding annotation is allowed.");
}
isFormEncoded = true;
}
}
// 处理Parameter级别Annotation
private ParameterHandler<?> parseParameter(
int p, Type parameterType, Annotation[] annotations) {
ParameterHandler<?> result = null;
for (Annotation annotation : annotations) {
ParameterHandler<?> annotationAction = parseParameterAnnotation(
p, parameterType, annotations, annotation);
...// handleException
result = annotationAction;
}
...// handleException
return result;
}
// 具体的处理Annotation的实现, 方法颇长就不贴详情了
private ParameterHandler<?> parseParameterAnnotation(
int p, Type type, Annotation[] annotations, Annotation annotation) {
if (annotation instanceof Url) { // handle @Url
...// throw Exception if necessary
gotUrl = true;
if (type == HttpUrl.class
|| type == String.class
|| type == URI.class
|| (type instanceof Class && "android.net.Uri".equals(((Class<?>) type).getName()))) {
return new ParameterHandler.RelativeUrl();
} else {
...// throw Exception
}
} else if (annotation instanceof Path) { // handle @Path
...// throw Exception if necessary
gotPath = true;
Path path = (Path) annotation;
String name = path.value();
validatePathName(p, name);
Converter<?, String> converter = retrofit.stringConverter(type, annotations); // 见Retrofit.stringConverter()
return new ParameterHandler.Path<>(name, converter, path.encoded()); // 见ParameterHandler.Path<>
} else if (annotation instanceof Query) { // handle @Query
} else if (annotation instanceof QueryName) { // handle @QueryName
} else if (annotation instanceof Header) { // handle @Header
} else if (annotation instanceof FieldMap) { // handle @FieldMap
} else if (annotation instanceof Part) { // handle @Part
} else if (annotation instanceof PartMap) { // handle @PartMap
} else if (annotation instanceof Body) { // handle @Body
}
return null; // Not a Retrofit annotation.
}
可见Retrofit对注解的处理分为两个部分: 一个是Method级别的Annotation, 所有http协议方法都被定义为该级别的Annotation, 在ServiceMethod.parseHttpMethodAndPath中处理(注意到, 基本方法DELETE GET HEAD POST等应该是互斥的, 但代码中没有进行判断, 而Multipard和FormUrlEncoded之间却进行了判断, 至于代码中没有对Streaming的处理, 是因为逻辑上它不在这一层, 而是在响应结果的解析, 所以其实是在retrofit2/BuiltInConverters.java中进行了处理); 另一个是Parameter级别的, 大多数是在进行基本预处理之后就委托给ParameterHandler接口的实现类进行处理.
通过对某个方法的注解的处理, 在ServiceMethod.Builder.build()完成后ServiceMethod就获取到了调用该方法发起网络请求所需要的信息, 可以开始构造Call了.
Retrofit的Call与Response
Retrofit的Call和Response是对OkHttp的Call和Response的封装, 为什么要进行这么一层封装呢? 接下来我们就看看它的源码.
我们选择从核心方法Retrofit.create(Class)开始.
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service); // #1
if (validateEagerly) {
eagerlyValidateMethods(service); // #2
}
// #3 below
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<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method); // #4
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args); // #5
return serviceMethod.callAdapter.adapt(okHttpCall); // #6
}
});
}
这里面一共有三个步骤, 其中前两步是用来检查接口和提前载入方法的, 第三步是关键, 生成并返回了一个代理. 实例化代理时传入了三个参数, 第三个是InvocationHandler的实现, 我们可以看到里面最关键的步骤是#4 #5 #6, 分别完成方法载入(Method->ServiceMethod), Call构造和返回Call代理. 这里Proxy及InvocationHandler都是Java中就已经存在并引入了Android中的机制, 即动态代理机制. 关于动态代理机制, 思想成熟战法犀利, 是相当有意思的一个东西, 可以参见这篇文章
总之要使用动态代理呢, 委托类必须要实现某个接口, 而Proxy创建的代理类通过实现InvocationHandler来调用委托类的方法, 完成代理. 所有这一切都跟反射密不可分, 所以理所当然Proxy是在反射包下的.
从上面代码可以看出, Platform.isDefaultMethod()和Object的方法将被InvocationHandler直接代理执行, 而其他方法则被包装成OkHttpCall交给ServiceMethod的CallAdapter去执行. 这里也可以看出对Call和Response进行封装代理的作用: 屏蔽底层实现, 统一处理非核心逻辑, 统一接口, 令底层替换成其他网络访问库成为可能.
下面我们来看ServiceMethod的构造过程, OkHttpCall的构造过程以及默认的CallAdapter的代码.
还记得在create里传入loadServiceMethod的是Method method, 它是代理方法, 通过它去访问委托(被代理)方法, 代码如下:
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(); // 传入Retrofit, Method实例, 构造代理包装类ServiceMethod实例
serviceMethodCache.put(method, result); // 缓存代理方法-代理包装实例映射
}
}
return result;
}
然后根据传入的方法及其参数, 构造一个合适的Call, 这个Call是OkHttp中Call的代理, 所以Retrofit中它的类是OkHttpCall. 下面我们看它是怎么构造和代理的, 代码如下:
final class OkHttpCall<T> implements Call<T> {
OkHttpCall(ServiceMethod<T, ?> serviceMethod, Object[] args) {
this.serviceMethod = serviceMethod;
this.args = args;
}
@Override public void enqueue(final Callback<T> callback) {
// 检查参数
okhttp3.Call call;
Throwable failure;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
call = rawCall;
failure = creationFailure;
if (call == null && failure == null) {
try {
call = rawCall = createRawCall();
} catch (Throwable t) {
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
call.enqueue(new okhttp3.Callback() { // okhttp3.Callback反向代理retrofit2.Callback
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {
Response<T> response;
try {
response = parseResponse(rawResponse); // 解析响应
} catch (Throwable e) {
callFailure(e); // 回调自身callFailure
return;
}
callSuccess(response); // 回调自身callSuccess
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
private void callSuccess(Response<T> response) {
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
}
}
结构清晰, 基本可以当做OkHttpCall来对待.
接下来通过ServiceMethod.callAdapter.adapt(OkHttpCall)将OkHttpCall转换为Call<T>. ServiceMethod的建造模式如下:
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations(); # 获取代理方法的方法注解
this.parameterTypes = method.getGenericParameterTypes(); # 获取泛型参数类型
this.parameterAnnotationsArray = method.getParameterAnnotations(); # 获取参数注解
}
public ServiceMethod build() {
callAdapter = createCallAdapter(); # 根据泛型返回类型和方法注解, 通过retrofit.callAdapter(returnType, annotations)寻找适配器实例. Retrofit实例化时默认添加`DefaultCallAdapterFactory`工厂
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?"); # 不允许以`Response`作为返回类型
}
responseConverter = createResponseConverter();
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation); # 解析方法注解
}
if (httpMethod == null) {
throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
...// 判断方法注解合法性
int parameterCount = parameterAnnotationsArray.length;
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);
}
ServiceMethod(Builder<R, T> builder) {
this.callFactory = builder.retrofit.callFactory();
this.callAdapter = builder.callAdapter;
this.baseUrl = builder.retrofit.baseUrl();
this.responseConverter = builder.responseConverter;
this.httpMethod = builder.httpMethod;
this.relativeUrl = builder.relativeUrl;
this.headers = builder.headers;
this.contentType = builder.contentType;
this.hasBody = builder.hasBody;
this.isFormEncoded = builder.isFormEncoded;
this.isMultipart = builder.isMultipart;
this.parameterHandlers = builder.parameterHandlers;
}
始终别忘了以上内容都是通过Java自带的Proxy机制调用InvocationHandler来代理的, 所以create传入的是什么类, 返回的就是什么类的代理, 访问这个代理的方法时, 实际调用的是InvocationHandler. 通过ServiceMethod.callAdapter.adapt()可以将传入的方法适配为你自己定义的返回类型Call<T>的实例. 我们来看看默认情况下添加的DefaultCallAdapterFactory会生成什么CallAdapter:
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) { // 工厂方法, 传入返回类型, 注解数组, retrofit实例
if (getRawType(returnType) != Call.class) { // 返回类型如果不是Call则直接返回null
return null;
}
final Type responseType = Utils.getCallResponseType(returnType); // 获取ReturnType<T>中泛型参数T的上限类型
return new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call<Object> adapt(Call<Object> call) {
return call; // 默认返回传入参数
}
};
}
显然默认情况下这个适配器什么也不做, 直接把传入的OkHttpCall返回给你.
Retrofit的Converter与CallAdapter: 开始使用RxJava
上文已经暗示了, 对结果的解析器Converter可以替换, 其实发送请求的代理Call也可以被替换, 只要换掉CallAdapter就可以了, 网上都说RxJava+Retrofit可以打出成吨输出, 原因就在于CallAdapter可以换成一个返回Observable类型的适配器, 这使得在Retrofit.create()之后可以直接以RxJava的风格做链式调用.
实现起来也非常简单, 只要.addConverterFactory() .addCallAdapterFactory()即可, 因为Retrofit对外提供了抽象类Converter.Factory CallAdapter.Factory, 并且实例全部使用泛型来表示, 通过对外提供统一接口, 只要外部可以继承抽象工厂类并返回实现了统一接口的实例类, 就可以在不改变Retrofit一行代码的情况下接入其他库, 或者原有逻辑代码变动不大的情况下接入Retrofit.
是时候上一波图了:

上面这张图是我基于Stay的这篇文章改的, 荣耀归他, 另外由于图滞后于
Retrofit版本, 所以如果有不一致的地方锅也归他(目前没看见不一致).
参考
这篇文章分析了Retrofit的实现, 其优缺点即使不是一目了然, 也是足够清晰了, 希望能够帮助到正在选择网络请求框架的各位.
本文参考如下: