Fork me on GitHub

Retrofit源码分析

Retrofit

A type-safe HTTP client for Android and Java

开发Android App肯定会使用Http请求与服务器通信,上传或下载数据等。目前开源的Http请求工具也有很多,比如Google开发的Volley,loopj的Android Async Http,Square开源的OkHttp或者Retrofit等。

我觉得Retrofit 无疑是这几个当中最好用的一个,设计这个库的思路很特别而且巧妙。Retrofit的代码很少,花点时间读它的源码肯定会收获很多。

本文的源码分析基于Retrofit 2,和Retrofit 1.0的Api有较大的不同, 本文主要分为几部分:Retrofit 是什么Retrofit怎么用Retrofit的原理是什么

Retorift 使用

官方使用简介

官方使用简介:(http://square.github.io/retrofit/)

引用依赖

1
2
// 最新版本 :2.5.0
implementation 'com.squareup.retrofit2:retrofit:(insert latest version)'

生成一个ApiService

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

创建Retorfit

1
2
3
4
5
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();

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

发起请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Call<List<Repo>> repos = service.listRepos("octocat");

//异步请求
// 请求数据,并且处理response
call.enqueue(new Callback<List<Repo>>() {
@Override
public void onResponse(Response<List<Repo>> response) {
System.out.println(response);
}
@Override
public void onFailure(Throwable t) {
}
});
//同步请求
call.execute()

ApiService 配置

Url配置

注解 描述 实例
@GET get请求 @GET(“group/users”)
@POST post请求 @POST(“group/users”)
@Uri Uri全连接配合 其他请求方法 @Uri(“http://xxxx/group/users“)
@PATH get/post 请求的动态路径,用于方法参数注解 @GET(“group/{id}/users” Call> groupList(@Path(“id”) int groupId);
@Headers 请求的 HEADER 作用于方法 @Headers(“Cache-Control: max-age=640000”)
@Header 请求的 HEADER 作用于方法参数 @Header(“Authorization”) String authorization
@Query & @QueryMap 用于方法参数注解,只能配合@GET Call> groupList(@Path(“id”) int groupId,@Query(“sort”) String sort);
@Body 用于方法参数注解 @POST(“users/new”)Call createUser(@Body User user);
@Field & @FieldMap 用于方法参数注解,只能配合@POST 类似@Query & @QueryMap
@Part & @PartMap 用于POST文件上传 Call updateUser(@Part(“photo”) RequestBody photo, @Part(“description”) RequestBody description);

其他高级用法

官方使用简介:(http://square.github.io/retrofit/)

Retrofit 源码分析

retrofit的最大特点就是解耦,要解耦就需要大量的设计模式,假如一点设计模式都不懂的人,可能很难看懂retrofit。

基本流程(组装过程)

Retrofit#create

1
ApiService service = retrofit.create(ApiService.class);

Retrofit是如何创建Api的,是通过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
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);
}
//DefaultMethod 是 Java 8 的概念,是定义在 interface 当中的有实现的方法
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//每一个接口最终实例化成一个 ServiceMethod,并且会缓存

ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
//Retrofit 与 OkHttp 完全耦合
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
//发起请求,并解析服务端返回的结果
return serviceMethod.adapt(okHttpCall);
}
});
}

提取在create方法中的关键几行代码 Service Proxy

当大家了解了动态代理之后, 都知道我们调用ApiService中的method都会自动调用 InvocationHandler().

真真开始执行的是 serviceMethod.adapt(okHttpCall)==> calladapter#adapt(okhttpCall);

1
2
3
4
 ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);

一个 ServiceMethod 对象对应于一个 API interface 的一个方法,loadServiceMethod(method) 方法负责加载 ServiceMethod:

1
2
3
4
5
6
7
8
9
10
11
12
13
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;
}

这里实现了缓存逻辑,同一个 API 的同一个方法,只会创建一次。这里由于我们每次获取 API 实例都是传入的 class 对象,而 class 对象是进程内单例的,所以获取到它的同一个方法 Method 实例也是单例的,所以这里的缓存是有效的。

ServiceMethod是什么呢???里面包含什么 ???
大致就是想这个方法的method转化成 ServiceMethod对象 包含 各个注解(方法的注解,参数的注解,方法的返回值的东西),那我们来看下具体有什么东西

我们看看 ServiceMethod 的构造函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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;
}

这里用了buider 模式,这里很多参数,有的参数一看就明白 像baseUrl,headers ,contyentType等,讲解主要关注四个成员:callFactory,callAdapter,responseConverter 和 parameterHandlers。

  • callFactory 负责创建 HTTP 请求,HTTP 请求被抽象为了 okhttp3.Call 类,它表示一个已经准备好,可以随时执行的 HTTP 请求;
  • callAdapter 把 retrofit2.Call 转为 T(注意和 okhttp3.Call 区分开来,retrofit2.Call 表示的是对一个 Retrofit 方法的调用),这个过程会发送一个 HTTP 请求,拿到服务器返回的数据(通过 okhttp3.Call 实现),并把数据转换为声明的 T 类型对象(通过 Converter 实现);
  • responseConverter 是 Converter 类型,负责把服务器返回的数据(JSON、XML、二进制或者其他格式,由 ResponseBody 封装)转化为 T 类型的对象;
  • parameterHandlers 则负责解析 API 定义时每个方法的参数,并在构造 HTTP 请求时设置参数;

retrofit2.ServiceMethod.Builder#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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
 public ServiceMethod build() {
// 通过method 找到对应的retrofit2.CallAdapter
callAdapter = createCallAdapter();
//省略代码...
// 通过method 找到对应的retrofit2.Converter
responseConverter = createResponseConverter();
//省略代码...
for (Annotation annotation : methodAnnotations) {
//解析 请求的方法
parseMethodAnnotation(annotation);
}
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);
}
```

### CallAdapter
> retrofit2.Retrofit.Builder#addCallAdapterFactory(Factory)

默认 retrofit2.DefaultCallAdapterFactory 使用的是OkhttpCall
+ `retrofit2.ServiceMethod.Builder#createCallAdapter(...)`
+ `retrofit2.Retrofit#callAdapter(...)`
+ `retrofit2.Retrofit#nextCallAdapter(null,...)`

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

int start = callAdapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
// 调用retrofit2.CallAdapter.Factory#get
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
//省略代码
//throw new IllegalArgumentException(builder.toString());
}

上面知道如果注册了多个retrofit2.CallAdapter,按照注册的顺序来执行,如果那个有返回值就会直接返回,不走for循环了

Converter

通过Retrofit 添加ConverterFactory
Retrofit.Builder#addConverterFactory(Factory)

默认retrofit2.BuiltInConverters

ParameterHandlers or RequestConverter

  • retrofit2.ServiceMethod.Builder#parseParameter(...)
  • retrofit2.ServiceMethod.Builder#parseParameterAnnotation(...)
    • retrofit2.Retrofit#stringConverter(...)
      • retrofit2.Converter.Factory#stringConverter(...)
      • OR retrofit2.Converter.Factory#requestBodyConverter(...)
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
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;
}
//省略代码 ...

result = annotationAction;
}
//省略代码 ...
return result;
}
private ParameterHandler<?> parseParameterAnnotation(int p, Type type, Annotation[] annotations, Annotation annotation) {
// 关键代码
Converter<?, String> converter =
retrofit.stringConverter(iterableType, annotations);

// or
Converter<?, RequestBody> converter =
retrofit.requestBodyConverter(type, annotations, methodAnnotations);
return new ParameterHandler;
}

【总结】: 当执行retrofit2.Retrofit#create(final Class<T> service)的时候就会找到对应的 retrofit2.Converter

responseConverter

  • retrofit2.ServiceMethod.Builder#createResponseConverter(...)
    • retrofit2.Retrofit#responseBodyConverter(...)
    • retrofit2.Retrofit#nextResponseBodyConverter(null,...)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
@Nullable 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++) {
// 调用 retrofit2.Converter.Factory#responseBodyConverter
Converter<ResponseBody, ?> converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
if (converter != null) {
//noinspection unchecked
return (Converter<ResponseBody, T>) converter;
}
}
...
//省略代码
// throw new IllegalArgumentException(...)
}

上面知道如果注册了多个Converter 按照注册的顺序来执行,如果那个有返回值就会直接返回,不走for循环了

【总结】: 当执行retrofit2.Retrofit#create(final Class<T> service)的时候就会找到对应的 retrofit2.Converter

以上都是初始化操作,将所有的请求相关的东西都封装到ServiceMethod

执行过程

1
serviceMethod.adapt(okHttpCall);

真正执行的开始点就是serviceMethod.adapt ,ServiceMethod.class执行过程中的 三个很重要,也是整个过程关键节点

1
2
3
4
5
6
7
8
9
10
11
12
// 简单粗俗的讲:返回包装okhttpCall后的对象
T adapt(Call<R> call) {
return callAdapter.adapt(call);
}
//retrofit2.OkHttpCall#createRawCall 调用
okhttp3.Call toCall(@Nullable Object... args) throws IOException {
// 返回 okhttp.Call
}
//retrofit2.OkHttpCall 请求结果之后 会调用 responseBody convert
R toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
}

通过serviceMethod上面三个方法,将 OkhttpCall,CallAdapter ,Converter 关联起来

为什么要用动态代理?

因为对接口的所有方法的调用都会集中转发到 InvocationHandler#invoke函数中,我们可以集中进行处理,更方便了。你可能会想,我也可以手写这样的代理类,把所有接口的调用都转发到 InvocationHandler#invoke,当然可以,但是可靠地自动生成岂不更方便,可以方便为什么不方便。

Retrofit分析-漂亮的解耦套路

Java动态代理

-------------本文结束感谢您的阅读-------------

本文标题:Retrofit源码分析

文章作者:zoudong

发布时间:2018年09月11日 - 09:09

最后更新:2019年03月16日 - 17:03

原始链接:http://blog.zoudongq123.cn/2018/09/11/Retrofit源码分析/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

分享