Retrofit原理简析

建议在分析Retrofit源码之前先了解OkHttp是基本原理,推荐阅读 OkHttp简析

基础用法

1
2
3
4
public interface WanAndroidApiService {
@GET("wxarticle/chapters/json")
Call<ResponseBody> getWxArticle();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//1
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://wanandroid.com/")
.build();
//2
WanAndroidApiService apiService = retrofit.create(WanAndroidApiService.class);
//3
Call<ResponseBody> call = apiService.getWxArticle();
//4
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
System.out.println(response.body().toString());
}

@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {

}
});

所以Retrofit同步/异步请求的步骤就是:

  1. 创建一个Retrofit
  2. 使用retrofit.create(XXXApiService.class)获取service(不是四大组件的service)
  3. 使用service构建一个Call
  4. 执行同步/异步请求,得到Response

步骤2是整个文章中最难的点

Retrofit

Retrofit中有三个重要的方法,build( )和create( )分别对应了步骤1和2

  • build( ) :
  • create( ) :
  • loadServiceMethod( ):负责解析注解的工作。

Retrofit#build( )

Retrofit类中采用了构建者设计模式,在build()方法中做了许多默认属性的配置以及参数的校验。

1
2
3
4
5
6
7
8
9
10
11
12
public Retrofit build() {	
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
.....
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}

例如:校验baseUrl、配置callFactory默认是OkHttpClient,配置converterFactories、adapterFactories、callbackExecutor。

Retrofit#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
27
28
29
30
31
public <T> T create(final Class<T> service) {
//a 验证接口是否合理
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
//b xxxApiService 中的方法调用都会走到这里
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
//c If the method is a method from Object then defer to normal invocation.
// 注释说 Object 的方法不管
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//d java8方法,我们不看
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//e 重点 构建一个ServiceMethod<Object, Object>对象
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
//f 重点 将参数和方法包装成OkHttpCall
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
//g 重点 将ServiceMethod和OkHttpCall绑定,返回了okHttpCall
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}

可以看到使用了动态代理设计模式。重写了invoke(Object proxy, Method method, @Nullable Object[] args)方法,传入我们需要实现的方法和参数,并返回我们需要的值。

在Retrofit#create( )方法中的重点是e、f和g。

Retrofit#loadServiceMethod()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
ServiceMethod<?, ?> loadServiceMethod(Method method) {
// 1
ServiceMethod<?, ?> result = serviceMethodCache.get(method);

if (result != null) return result;

synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
// 2
result = new ServiceMethod.Builder<>(this, method).build();
// 3
serviceMethodCache.put(method, result);
}
}
return result;
}

这个方法做了几个操作:

  1. 从取缓存serviceMethodCache
  2. 假如缓存为空,则构建ServiceMethod result;
  3. 将result放入缓存

所以此方法的重点是步骤2,先看看这个ServiceMethod.class

ServiceMethod

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
final class ServiceMethod<R, T> {
final okhttp3.Call.Factory callFactory;
final CallAdapter<R, T> callAdapter;

private final HttpUrl baseUrl;
private final Converter<ResponseBody, R> responseConverter;
private final String httpMethod;
private final String relativeUrl;
private final Headers headers;
private final MediaType contentType;
private final boolean hasBody;
private final boolean isFormEncoded;
private final boolean isMultipart;
private final ParameterHandler<?>[] parameterHandlers;
}

可以看到:ServiceMethod类中存储着一个请求所需要的所有数据!但是此时还未构建Request!,真正构建Request是在OkHttpCall#rawCall()方法中,调用的是

ServiceMethod有三个重要的方法:

  1. ServiceMethod.Builder<>()
  2. ServiceMethod#build()
  3. ServiceMethod#toRequest()

我们先进入ServiceMethod.Builder<>(this, method)

ServiceMethod.Builder<>()

1
2
3
4
5
6
7
8
9
10
11
12
//ServiceMethod.class
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
//接口方法
this.method = method;
//接口方法的注解,XXXApiService.class中的@GET @POST之类
this.methodAnnotations = method.getAnnotations();
//参数类型
this.parameterTypes = method.getGenericParameterTypes();
//参数注解数组
this.parameterAnnotationsArray = method.getParameterAnnotations();
}

builder(this,method)方法获取了这些需要的参数。

ServiceMethod#build( )

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
//ServiceMethod.class
public ServiceMethod build() {
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
responseConverter = createResponseConverter();

for (Annotation annotation : methodAnnotations) {
// 1 遍历方法的注解,解析出 httpMethod,relativeUrl,hasBody等属性。
parseMethodAnnotation(annotation);
}
...
int parameterCount = parameterAnnotationsArray.length;
//2 创建解析参数的注解数组
parameterHandlers = new ParameterHandler<?>[parameterCount];

for (int p = 0; p < parameterCount; p++) {
//3 遍历参数类型
Type parameterType = parameterTypes[p];
if (Utils.hasUnresolvableType(parameterType)) {
throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
parameterType);
}
// 4 获取参数注解
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
if (parameterAnnotations == null) {
throw parameterError(p, "No Retrofit annotation found.");
}
//5 将3和4 获取的参数类型、参数注解一起进行解析。将结果存入parameterHandlers
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}

...
//6 创建ServiceMethod对象
return new ServiceMethod<>(this);
}

所以ServiceMethod#build()方法是负责解析注解,并将结果存储在ServiceMethod对象的各个属性里。

ServiceMethod#toRequest( )

构建一个Request,在后面OkHttpCall#createRawCall()方法中被调用。

OkHttpCall

再回到Retrofit#create()方法的步骤f中,

OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);

1
2
3
4
5
6
7
8
9
10
11
12
13
final class OkHttpCall<T> implements Call<T> {
private final ServiceMethod<T, ?> serviceMethod;
private final @Nullable Object[] args;

private volatile boolean canceled;
private okhttp3.Call rawCall;
private Throwable creationFailure;
private boolean executed;

OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {
this.serviceMethod = serviceMethod;
this.args = args;
}

OkHttpCall的成员变量rawCall是okhttp3.Call,且内部enqueue( )和execute( ) 方法最终都是调用了rawCall的异步请求和同步请求方法。

OkHttpCall.enqueue( )

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
//OkHttpCall.class

@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "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 {
// 1
call = rawCall = createRawCall();
} catch (Throwable t) {
failure = creationFailure = t;
}
}
}

if (failure != null) {
callback.onFailure(this, failure);
return;
}

if (canceled) {
call.cancel();
}
// 2
call.enqueue(new okhttp3.Callback() {
//...省略具体实现
});
}
  1. 调用OkHttpCall#createRawCall()构建真正的请求OkHttp3.Call对象call
  2. 调用call的异步请求方法

OkHttpCall.execute( )

和异步请求方法类似,先构建真正的请求call,然后调用call的同步请求方法。

OkHttpCall#createRawCall()

1
2
3
4
5
6
7
8
9
10
private okhttp3.Call createRawCall() throws IOException {
// 1
Request request = serviceMethod.toRequest(args);
// 2 serviceMethod.callFactory默认为OkHttpClient
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}

所以OkHttpCall#createRawCall()方法进行了如下操作。

  1. 调用ServiceMethod#toRequest(args)构建了一个Request
  2. 调用OkHttpClient#newCall(request)构建了call

总结

流程图

Retrofit在create()方法中采用动态代理设计模式实现接口方法,在create方法中通过ServiceMethod#build()方法解析注解,获取到请求方式、参数类型、参数值等信息。在Call#enqueue()方法里最终调用了ServiceMethod#toRequest()构建了真正的Request,然后调用OkHttpClient#newCall(request)获取了OkHttp3.Call,最终调用call的enqueue()进行了异步请求

整个流程中,最难的应该是Retrofit在create()方法,希望大家有空多看看,可以自己也画一个流程图。