闭门造车姚师傅

Retrofit 源码分析:代码结构

字数统计: 2.9k阅读时长: 13 min
2018/02/03 Share

好的代码是自解释的,Retrofit 可以算是好的代码了。

Retrofit 的依赖图
Retrofit 的依赖图

一、无中生有:从接口方法到Request实例

ServiceMethod.java

将 API接口 中定义的方法方法转化为 HTTP 请求。接口中描述的方法是没有方法体的,所以最终执行的时候需要根据接口信息去组织特定的方法和对象,以产生可以执行的代码。

1
2
3
4
5
6
@Headers({
"X-Foo: Bar",
"X-Ping: Pong"
})
@POST("/abc")
Call<ResponseBody> getSomething(@Body String body);

ServiceMethod 虽然没有继承自 java.lang.reflect.Method,但是同样提供了执行方法的途径。由内部类 Builder 中的 parseMethodAnnotation(Annotation annotation)/*参见 Retrofit源码分析:方法注解*/ , parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) , parseHeaders(String[] headers) , parseParameter(...) , parseParameterAnnotation(...) 等方法来转换成一个“有血有肉”的 OkHttp 请求。

一段很有意思的代码:

  • @Path 注解表示的 URL 不能和参数化查询混淆(形如/{name}/address?type=home)#294 ~ #303
1
2
3
4
5
6
7
8
9
10
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); //REGEX: {([a-zA-Z][a-zA-Z0-9_-])*}
if (queryParamMatcher.find()) {
throw methodError("URL query string \"%s\" must not have replace block. "
+ "For dynamic query parameters use @Query.", queryParams);
}
}

RequestBuilder.java

负责构建 Request 对象的具体实现。分离职责

ServiceMethod 中有个 “根据方法参数构建 HTTP 请求” 的方法,就是把从接口方法中解析到的数据传到这里来创建请求的。目前只有构建 Request 实例的过程中用到了这个类。

主要有下面这些方法,这些方法都是 ParameterHandler 在用。

使用 IntelliJ / Android Studio 快捷键 alt+f7 可以快速查找依赖 (要把 作用域Scope 设置为 Project and Libraries )

Retrofit Builder 关键方法

ParameterHandler.java

负责处理参数,是具体实现。分离职责

里面有一些内部类:RelativeUrl , Header , Path , Query , QueryName , QueryMap , HeaderMap , Field , FieldMap , Part , RawPart , PartMapBody 等内部类。

这些内部类都继承自 ParameterHandler , 并重写了 apply() (也是唯一一个可供重写的方法)。这些类的实例供 ServiceMethod 使用。

目前只有构建 Request 实例的过程中用到了这个类。


二、 天堑变通途,Request 和 Response

Call.java

每次调用 Retrofit 方法会向服务器发起请求并得到一个响应。

在 Retrofit 中,仅有一个实现类:OkHttpCall。Retrofit 通过动态代理使用的也有一个类,即所有的 Retrofit中的所有接口方法使用的都是 OkHttpCall 。见 Retrofit 中的 public <T> T create(final Class<T> service) 方法。

接口共有七个方法,Response<T> execute()void enqueue(Callback<T> callback) 分别同步、异步发出请求;void cancle() 用来取消请求; boolean isExecuted()boolean isCanceled() 用来获取当前请求的状态;Retrofit 中每个请求只能执行一次,当需要轮询或者失败重传的时候,可以使用 Call.clone() 来产生同样的请求;Request request() 可以获取生成的 Request 对象(并没有执行 request,而是一个 getter 方法, retrofit 中好多(可能是所有) getter 方法都是这种风格的,方法名不以 get 开头)。

OkHttpCall.java

Call 的唯一实现类

executeenqueue 的代码片段(一个 Call 只能执行一次):

1
2
if (executed) throw new IllegalStateException("Already executed.");
executed = true;

executeenqueue 函数的结构很相似,拿 enqueue 来说(移除了错误处理代码,并 inline 了部分函数):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Override public void enqueue(final Callback<T> callback) {
okhttp3.Call call;
synchronized (this) {
call = rawCall; // rawCall 是全局变量

if (canceled) { call.cancel(); }

call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse throws IOException {
Response<T> response = parseResponse(rawResponse);
}
callback.onResponse(OkHttpCall.this, response);
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
callback.onFailure(OkHttpCall.this, e);
}
}

可以看到这个方法中进行了一次复制,使用原来的 call 并间接调用了 callback 。为什么要这样多此一举呢?这跟 Retrofit 请求道路的曲折性是分不开的。当 通过 OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) 这个构造方法创建对象后,得到的 call 对象就是个简单的对象而已,无法完成网络请求,需要在内部通过callFactory 创建。

createRawCall 根据构造函数中传入的 args , 创建新的 request ,并根据 request 创建 Call (代码中出现的 callFactory 默认情况下是 Retrofit 创建的 ,真正的实例是 OkHttpClient ,这个类实现了 Call.Factory 接口 。OkHttpClient 中的实现是 return RealCall.newRealCall(this, request, false /* for web socket */) 。很明显,真正进行请求的是RealCall ,代码中的 rawCall 的类型一般情况就是 RealCall 啦!这也就说通了为什么会有这么一层包装,因为 OkHttpCall 就是个中间层!):

1
2
3
4
5
6
7
8
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;
}

解析响应 response , 所有的分支都是 return Response.success/error(...) 的形式, Response 类中 successerror 的几个静态重载方法会返回带有泛型的 Response

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
// 不是所有的响应 body 都有意义,这里先把它拿掉
ResponseBody rawBody = rawResponse.body();
rawResponse = rawResponse.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();

int code = rawResponse.code();
if (code < 200 || code >= 300) { // “非成功”状态码
try { //
ResponseBody bufferedBody = Utils.buffer(rawBody); // wtf…
return Response.error(bufferedBody, rawResponse); // 返回出错响应
} finally {
rawBody.close();
}
}

if (code == 204 || code == 205) { // 服务器成功处理了请求,没有返回任何内容。
rawBody.close();
return Response.success(null, rawResponse); // 返回成功响应,body 为 null
}

// 2xx but 204 205, 用到了之前取出的 body
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
T body = serviceMethod.toResponse(catchingBody);
return Response.success(body, rawResponse); // 我们最关心的一行
} catch (RuntimeException e) {
catchingBody.throwIfCaught();
throw e;
}
}

Callback.java

对于绝大多数 Android开发者来说,这个接口是相当熟悉的。

onResponse & onFailure 分别对应请求成功和失败

Response.java

okhttp3.Response 的一个简单封装

包含一些 getter 方法(delegate)和几个用来创建 Response 的静态方法(successerror 的重载方法)。


三、Factory、Adapter、Converter

Converter.java

此接口包含了一个方法:T convert(F value) 和一个抽象内部类 FactoryFactory 产生特定的 Converter

Factory 有三个可供重写的方法:

  • responseBodyConverter(Type type,Annotation[] annotations, Retrofit retrofit)
  • requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit)

    返回处理 HTTP Request 的 Converter ,某种类型(在接口方法的声明中一般被 PartBodyPartMap 修饰)的对象 –> HTTP Request Body

  • stringConverter(Type type, Annotation[] annotations, Retrofit retrofit)

    返回将某种类型转化为 StringConverter ,某种类型(在接口方法的声明中一般被 Field/FieldMapHeader/HeaderMapQuery/QueryMapPath 修饰) –> String 。因为 HTTP 1.1 的 URL / Body / Header 是建立在字符串上的

对于不能/不想处理的数据类型,直接返回 null 就可以了(这也是这些方法的默认实现)。Retrofit 将继续查找适用的 Converter 或者采用一个默认实现。

BuiltInConverters.java

  • VoidResponseBodyConverter.class
  • RequestBodyConverter.class
  • StreamingResponseBodyConverter.class
  • BufferingResponseBodyConverter.class
  • ToStringConverter.class

CallAdapter.java

比如我们本来只能写返回 Call<Foo> 这样的方法,但是在 CallAdapterRxJava2CallAdapterFactory , 'com.squareup.retrofit2:adapter-rxjava2:2.3.0')的帮助下,我们可以写返回 Observable<UsersResponse>这种的方法。

同样有个名为 Factory 的内部类

  • T adapt(Call<R> call); /* Call<R> --> Foo<R> */

返回一个真正执行(delegate,代理)这个 Call 的实例。比如:

1
2
3
4
5
6
7
8
9
@Override
public <R> Async<R> adapt(final Call&lt;R> call) {
return Async.create(new Callable<Response<R>>() {
@Override
public Response<R> call() throws Exception {
return call.execute();
}
});
}
  • Type responseType();

举个简单的例子,如果接口声明的是 Call<Foo> ,那么这里应该返回 Foo

Retrofit 内置的两个 CallAdapter ,都有这样的代码:

1
2
3
if (getRawType(returnType) != Call.class) {
return null;
}

意味着默认情况下仅仅能处理 Call<Foo> 这种返回值的接口方法

DefaultCallAdapterFactory.java

创建那种 Adapter,就是 I/O 和 Callback 执行在同一个线程上那种

由于是这里的 I/O 几乎等于网络请求,所以 Android 一般情况下是不会用到这个的。

ExecutorCallAdapterFactory.java

这个类的adapt(...) 方法将 call 外包给自己的内部类:ExecutorCallbackCall

看到这个 Executor ,em……, 没错,就是 java.util.concurrent.Executor

四、Retrofit、Platform

##Retrofit.java

Retrofit , Retrofit, Retrofit

一切的入口,Retrofit 家的门面

  • 构造函数
1
Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,    List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories,    @Nullable Executor callbackExecutor, boolean validateEagerly);
  • public Builder newBuilder()

    em…… new Retrofit.Builder().build() 就是 Retrofit 了 。

  • public <T> T create(final Class<T> service)

    根据接口信息使用反射生成对应的对象,要求 service.isInterface() 并且不能继承其他接口。

  • private void eagerlyValidateMethods(Class<?> service)

    如果 validateEagerlytrue,Retrofit将在反射之前来验证并加载接口中的方法。

  • ServiceMethod<?, ?> loadServiceMethod(Method method)

    java.lang.reflect.Method 加载为 retrofit2.ServiceMethod

  • callAdapter 相关

    1
    2
    public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations);
    public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations);
  • converter 相关

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // a naive getter
    public List<Converter.Factory> converterFactories();

    // 根据参数查找一个合适的 Converter
    public <T> Converter<T, RequestBody> requestBodyConverter(Type type,
    Annotation[] parameterAnnotations, Annotation[] methodAnnotations);
    public <T> Converter<T, RequestBody> nextRequestBodyConverter(
    @Nullable Converter.Factory skipPast, Type type, Annotation[] parameterAnnotations,
    Annotation[] methodAnnotations);
    public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations);
    public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
    @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations);
    public <T> Converter<T, String> stringConverter(Type type, Annotation[] annotations)
  • getters 相关

    1
    2
    3
    4
    5
    public HttpUrl baseUrl();
    public okhttp3.Call.Factory callFactory();
    public List<CallAdapter.Factory> callAdapterFactories();
    public List<Converter.Factory> converterFactories();
    public @Nullable Executor callbackExecutor();

简单看下 create 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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)) { // 默认为 false,Android 下为 fasle
return platform.invokeDefaultMethod(method, service, proxy, args);
}
// 根据接口方法信息构建等价的 ServiceMethod
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
// 根据 ServiceMethod 构建响应的 Call
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall); // 这里是个 Object, 如果接口方法返回值类型为Call<Foo>,则此返回值的类型为 Foo
}
});
}

Platform.java

不同的平台有不同的行为,上面提到的 adapterconverter 等细节方面也是存在差异的。比如 Android 平台在系统层面上限制在 UI 线程上进行网络请求。

这个类有两个内部类:Java8 extends PlatformAndroid extends Platform

对于 Java8,跟 callback 有关的是默认实现:

1
2
3
4
5
6
7
8
9
10
@Nullable Executor defaultCallbackExecutor() {
return null; // 没有回调 Executor
}

CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
if (callbackExecutor != null) { // false
return new ExecutorCallAdapterFactory(callbackExecutor);
}
return DefaultCallAdapterFactory.INSTANCE; // 所以使用的是 DefaultCallAdapterFactory
}

而对于 Android,对应的实现则是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor(); // 有回调 Executor
}
@Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
if (callbackExecutor == null) throw new AssertionError();
return new ExecutorCallAdapterFactory(callbackExecutor);
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
// Callback 在 UI 线程上执行 ,
// 不然可能就 android.view.ViewRoot$CalledFromWrongThreadException:
// Only the original thread that created a view hierarchy can touch its views.
handler.post(r);
}
}

对着代码中嵌入的文档,和胡猜各种命名,终于把这个项目捋下来了。
可能是市面上相当详细全面的一篇了,当然很多地方还是不够详细。因为代码实在是不少,贴进来肯定是一篇“巨作”。但是结构还算清晰,如果你也感兴趣,打开你的 Android Studio / IntelliJ Idea 也来看看吧!


Ref:

via boileryao

Happy coding :)

CATALOG
  1. 1. 一、无中生有:从接口方法到Request实例
    1. 1.1. ServiceMethod.java
    2. 1.2. RequestBuilder.java
    3. 1.3. ParameterHandler.java
  2. 2. 二、 天堑变通途,Request 和 Response
    1. 2.1. Call.java
    2. 2.2. OkHttpCall.java
    3. 2.3. Callback.java
    4. 2.4. Response.java
  3. 3. 三、Factory、Adapter、Converter
    1. 3.1. Converter.java
    2. 3.2. BuiltInConverters.java
    3. 3.3. CallAdapter.java
    4. 3.4. DefaultCallAdapterFactory.java
    5. 3.5. ExecutorCallAdapterFactory.java
  4. 4. 四、Retrofit、Platform
    1. 4.1. Platform.java