闭门造车姚师傅

Retrofit 源码分析:代码结构

字数统计: 2.9k阅读时长: 13 min
2018/02/03 334 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 :)

Powered By Valine
v1.5.2
CATALOG
  1. 1. 一、无中生有:从接口方法到Request实例
  2. 2. 二、 天堑变通途,Request 和 Response
  3. 3. 三、Factory、Adapter、Converter
  4. 4. 四、Retrofit、Platform