Retrofit源码分析

基本概念

最近把之前看过的Retrofit的源码翻出来研究一下。

Retrofit现在不像两年前是个新鲜事物,大版本已经到Retrofit2了,越来越多的新项目和开源项目会理所应当地使用OkHttp + Retrofit + RxJava + Gson这一套进行网络请求,这也侧面反映了Retrofit的强大(插一句,这几个库厉害不代表会用就厉害,其实用了就知道,这几个的搭配使用的优势就是傻瓜化)。优秀的框架在使用和扩展上会越来越简单,同时又会更强大,在我看来Retrofit相对于Volley以及更早的框架就是这样。而这时候只会用是不够的,知其然且知其所以然,才能真正学到本事。

这篇分析基于Retrofit2.2.0。

基本流程

这里就不自己画了,借助stay大神的图,毕竟这张图画的太完美了:

源码分析

还是以官方的示例代码来看:

1
2
3
4
5

public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}

这个接口用过Retrofit的都算是很熟了,然后再用Retrofit创建一个接口的实现:

1
2
3
4
5
6

Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();

GitHubService service = retrofit.create(GitHubService.class);

这里是一个明显的建造者模式+外观模式,也算是如今许多开源项目的套路了。然后是进行网络请求了:

1
2

Call<List<Repo>> repos = service.listRepos("octocat");

官网的示例到此结束,一般情况下使用Retrofit都是这么个套路,最多就是在配置时加上Gson或者RxJava。接下来我们开始分析源码,还是从入口开始,关键点在创建API实例的create(class)方法,我们看这部分源码:

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, 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);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}

这里我刚开始看的时候完全不明白,在查了InvocationHandler相关的知识之后才了解这里用到了Java的动态代理技术。在这里,就是动态生成我们所写的API接口的实现类,创建一个实例,然后把对方法的调用转发给new出来的InvocationHandler,在invoke方法中执行接口实现类的逻辑。
然后我们再看其中的具体逻辑。第一步中源码有注释,如果调用的是Object类的方法(toString这些),那就直接调用。第二步如果是default方法就调用default方法,这个default方法来自Java8,具体见这篇Java8 默认方法。然后就是关键部分了,因为我们在使用的时候不可能是前两种情况,我们调用的都是我们自己写的接口的方法,接下来这几行代码就是请求的具体过程了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);

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();
serviceMethodCache.put(method, result);
}
}
return result;
}

loadServiceMethod方法里创建了一个ServiceMethod的实例,并且在中间实现了缓存逻辑。然后再看ServiceMethod里的逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

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;
}

通过ServiceMethod的构造方法,我们基本能知道这个类的成员变量都有哪些。首先看我们比较眼熟的两个成员变量,responseConvertercallAdapter,因为搭配使用过RxJava + Retrofit + Gson的人都知道在创建Retrofit实例的时候是这么写的:

1
2
3
4
5
6

Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();

先看 ServiceMethodcallAdapter相关的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

private CallAdapter<T, R> createCallAdapter() {
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError("Service methods cannot return void.");
}
Annotation[] annotations = method.getAnnotations();
try {
//noinspection unchecked
return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create call adapter for %s", returnType);
}
}

可以看到这个成员变量的callAdapter还是由Retrofit来提供,在Retrofit类内部有这样一个方法:

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
33
34

public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}

public CallAdapter<?, ?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
checkNotNull(returnType, "returnType == null");
checkNotNull(annotations, "annotations == null");

int start = adapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = adapterFactories.size(); i < count; i++) {
CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}

StringBuilder builder = new StringBuilder("Could not locate call adapter for ")
.append(returnType)
.append(".\n");
if (skipPast != null) {
builder.append(" Skipped:");
for (int i = 0; i < start; i++) {
builder.append("\n * ").append(adapterFactories.get(i).getClass().getName());
}
builder.append('\n');
}
builder.append(" Tried:");
for (int i = start, count = adapterFactories.size(); i < count; i++) {
builder.append("\n * ").append(adapterFactories.get(i).getClass().getName());
}
throw new IllegalArgumentException(builder.toString());
}

在这里会遍历一个CallAdapter.Factory的列表,直到找到可用的工厂,我们在构建Retrofit时传入的RxJavaCallAdapterFactory就是在这里要使用的。然后再看responseConverter这个成员变量的相关方法:

1
2
3
4
5
6
7
8
9

private Converter<ResponseBody, T> createResponseConverter() {
Annotation[] annotations = method.getAnnotations();
try {
return retrofit.responseBodyConverter(responseType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create converter for %s", responseType);
}
}

看起来还是由Retrofit来提供:

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
33
34
35
36

public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
return nextResponseBodyConverter(null, type, annotations);
}

public <T> Converter<ResponseBody, T> nextResponseBodyConverter(Converter.Factory skipPast,
Type type, Annotation[] annotations) {
checkNotNull(type, "type == null");
checkNotNull(annotations, "annotations == null");

int start = converterFactories.indexOf(skipPast) + 1;
for (int i = start, count = converterFactories.size(); i < count; i++) {
Converter<ResponseBody, ?> converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
if (converter != null) {
//noinspection unchecked
return (Converter<ResponseBody, T>) converter;
}
}

StringBuilder builder = new StringBuilder("Could not locate ResponseBody converter for ")
.append(type)
.append(".\n");
if (skipPast != null) {
builder.append(" Skipped:");
for (int i = 0; i < start; i++) {
builder.append("\n * ").append(converterFactories.get(i).getClass().getName());
}
builder.append('\n');
}
builder.append(" Tried:");
for (int i = start, count = converterFactories.size(); i < count; i++) {
builder.append("\n * ").append(converterFactories.get(i).getClass().getName());
}
throw new IllegalArgumentException(builder.toString());
}

大体逻辑毫无二致。
ServiceMethod里另外两个比较关键的成员变量分别是callFactoryparameterHandlerscallFactory本质是okhttp3.Call.Factory,在Retrofit的构建过程中也可以传入自己实现的okhttp3.Call.Factory,如果没有,则会默认创建一个OkHttpClient。再看parameterHandlers

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

private ParameterHandler<?> parseParameter(
int p, Type parameterType, Annotation[] annotations) {
ParameterHandler<?> result = null;
for (Annotation annotation : annotations) {
ParameterHandler<?> annotationAction = parseParameterAnnotation(
p, parameterType, annotations, annotation);

if (annotationAction == null) {
continue;
}

if (result != null) {
throw parameterError(p, "Multiple Retrofit annotations found, only one allowed.");
}

result = annotationAction;
}

if (result == null) {
throw parameterError(p, "No Retrofit annotation found.");
}

return result;
}

因为我们我们在写业务层的API时都是通过注解传入参数的,它的作用就是解析每个参数使用的注解类型并进行处理。到这里ServiceMethod这部分基本解释结束。在这个类里面,核心的就是三个工厂:okhttp3.Call.FactoryCallAdapter.FactoryConverter.Factory,核心的模块全部交给工厂来做,外界可以通过传入自己的工厂实现对流程的完全控制,真正做到了高内聚低耦合(虽然在我看来okhttp3.Call.Factory还是有点强依赖于OkHttp)。
ServiceMethod看完了,再看OkHttpCall。它实现了retrofit2.Call接口,execute()enqueue(callback)这两种请求都是在这里来做。先看execute():

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

@Override public Response<T> execute() throws IOException {
okhttp3.Call call;

synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;

if (creationFailure != null) {
if (creationFailure instanceof IOException) {
throw (IOException) creationFailure;
} else {
throw (RuntimeException) creationFailure;
}
}

call = rawCall;
if (call == null) {
try {
call = rawCall = createRawCall();
} catch (IOException | RuntimeException e) {
creationFailure = e;
throw e;
}
}
}

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

return parseResponse(call.execute());
}

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<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 {
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;
}
}

execute()方法里的代码并不多,其实就是一个构造请求、请求网络、解析返回数据的过程。在createRawCall()的时候就可以用serviceMethodcallFactory来构造具体请求。在处理返回数据的时候responseConverter也就派上了用场。

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

@Override public void enqueue(final Callback<T> callback) {
if (callback == null) throw new NullPointerException("callback == null");

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() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {

Response<T> response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
callSuccess(response);
}

@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();
}
}
});
}

代码看起来长,但是大体逻辑与同步请求没有本质区别,只是在异步的callback里进行返回数据的处理。到这里,一次完整的请求就完成了。

总结

其实Retrofit的诱人之处完全不止于此,许多人使用Retrofit都是冲着RxJavaCallAdapterFactoryGsonConverterFactory去的,如果有更深的兴趣,可以读一下这些Factory的具体实现的代码,因为不只有RxJavaCallAdapterFactoryGsonConverterFactory这两个,还有Java8CallAdapterFactoryJacksonConverterFactory这些工厂。当然我们也可以根据需求写我们自己的工厂。另外Retrofit里的CallAdapter默认使用的是OkHttp,我们完全也可以用其他的框架替代OkHttp。Retrofit除了充足的扩展性,另一个就是它对设计模式的灵活运用,包括刚开始提到的门面模式,建造者模式,还有工厂模式,另外在这些工厂的具体实现里还有策略模式和装饰模式。具体可以看这一篇Retrofit分析-经典设计模式案例。总之,Retrofit确实是一个优质的网络封装库,而且它用不多的代码却实现了模块的完全解耦和充分的扩展性,源码很值得一读。