Retrofit源码分析

Posted by alonealice on 2017-05-17

Retrofit 是安卓上最流行的HTTP Client库之一,它因其出色的性能和简洁的实现广受开发者好评,那么现在就来看看它的实现原理。

使用方法

具体的使用方法,我在这里不再赘述,大家可以直接看它的官方文档 Retrofit官方文档,里面讲的非常简洁具体。

实现原理

在具体了解原理之前,我们先看看认真看完这一篇,不懂 Retrofit?不存在的(源码解析这篇文章中分享的Retrofit简易流程架构图:
Retrofit流程图
下面我们来看看具体的代码实现。

1
2
3
4
5
6
7
8
9
10
Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories,
Executor callbackExecutor, boolean validateEagerly) {
this.callFactory = callFactory;
this.baseUrl = baseUrl;
this.converterFactories = unmodifiableList(converterFactories); // Defensive copy at call site.
this.adapterFactories = unmodifiableList(adapterFactories); // Defensive copy at call site.
this.callbackExecutor = callbackExecutor;
this.validateEagerly = validateEagerly;
}

通过源码我发现,Retrofit的构造方法需要传入的参数较多,所以其采用了Builder模式来传入参数。

Retrofit Builder类

Builder类在创建Retrofit实例的过程中,主要需要传入一下几个参数:baseUrl、client、addConverterFactory、addCallAdapterFactory。下面依次来讲一下这些参数的意义。
baseUrl:这个顾名思义,就是请求的基础Url;client:这个是OkHttpClient的对象,也就是具体进行网络请求的对象。addConverterFactory:这个就是生产Converter的工厂类,也就是生产在请求过程中对请求数据和回调数据进行转换的转换器的工厂类,主要是处理 ResponseBody, RequestBody 和 String类型的转化;addCallAdapterFactory:这个是生产CallAdapter的工厂类。Call就是用来真正发起网络请求和接收回调的,而CallAdapter是将一个Call适配给另一个Call的适配器接口。对于后面两个工厂类可能还不是很清楚,这些会在后面讲具体实现中再讲它们是怎么用的。

Retrofit create方法

create方法是整个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
@SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
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 serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}

开始的代码跟核心功能关系不大,先简单说说。首先是检查传入的是的是inteeface类。其次是根据需要创建所有接口的ServiceMethod,ServiceMethod是什么我们后面再说,而这个默认是关闭的,因为在创建ServiceMethod时是需要耗费时间和性能,所以一般不需要在一开始时就将所有请求的ServiceMethod就全部创建。接下来就是根据动态代理的方式来创建接口对象,这也是create方法的核心所在,那我们再来看看这里面做了什么。
首先如果是Object的方法就不管,其次如果是default 方法也不管。这里的default方法是java 8的新特性,在这里不做介绍。然后就是最关键的3行代码,接下啦我们就重点看看这几行代码。
loadServiceMethod(method)在之前其实遇到过,创建接口的ServiceMethod。那什么是ServiceMethod呢?ServiceMethod就是根据接口的注解、传入参数等信息来创建的类,这里面包含着请求接口的请求方式、参数、请求header、url等等信息。除了这些以外,还有几个变量值得关注。
1.callFactory 它负责创建并执行Http请求。
2.callAdapter 它主要是把请求数据retrofit2.Call<T>转化为相应的T,而我们发现,ServiceMethod中的callAdapter其实就来自于一开始我们在初始化Retrofit时addCallAdapterFactory所传入的工程类所创建。
3.responseConverter 它负责把服务器返回的数据(JSON、XML、二进制或者其他格式,由 ResponseBody 封装)转化为 T 类型的对象,同样,它也是Retrofit初始化时addConverterFactory所传入的工程类所创建。
同时,Retrofit还对ServiceMethod进行了缓存,方便同一个接口调用时可以更快速。
然后是创建OkHttpCall。OkHttpCall是OkHttp的包装类,所有OkHttp所需要的参数都需要在创建时传入。
最后是最关键的serviceMethod.callAdapter. adapt(okHttpCall)。这里我用的是RxJavaCallAdapterFactory这个工厂类,RxJavaCallAdapterFactorygetCallAdapter方法中对返回值的泛型类型进行了进一步检查,例如我们声明的返回值类型为Observable<List<Repo>>,泛型类型就是List<Repo>,这里对 retrofit2.Responseretrofit2.adapter.rxjava.Result进行了特殊处理,有单独的 adapter 负责进行转换,其他所有类型都由 SimpleCallAdapter 负责转换。所以CallAdapter就是SimpleCallAdapter,那就先来看看SimpleCallAdapter中的adapt方法。

1
2
3
4
5
6
7
8
9
@Override public <R> Observable<R> adapt(Call<R> call) {
Observable<R> observable = Observable.create(new CallOnSubscribe<>(call)) //
.lift(OperatorMapResponseToBodyOrError.<R>instance());
if (scheduler != null) {
return observable.subscribeOn(scheduler);
}
return observable;
}
}

这里的实现方式也很简单,创建了一个Observable,并由CallOnSubscribe去实现逻辑,同时用OperatorMapResponseToBodyOrErrorretrofit2.Response转化为声明的类型或者错误异常类型。

1
2
3
4
5
6
7
8
9
10
11
@Override public void call(final Subscriber<? super Response<T>> subscriber) {

// Since Call is a one-shot type, clone it for each new subscriber.
Call<T> call = originalCall.clone();

// Wrap the call in a helper which handles both unsubscription and backpressure.
RequestArbiter<T> requestArbiter = new RequestArbiter<>(call, subscriber);
subscriber.add(Subscriptions.create(requestArbiter));
subscriber.setProducer(requestArbiter);
}
}

CallOnSubscribe中call的实现也很简洁,首先将okhttp3.Callclone,因为它只能使用一次,所以每次都是新的clone进行请求。然后创建了RequestArbiter,并将其设置给subscriber
Subscriber设置Producer之后,Subscriber会通过Producer去请求数据,而Producer请求到数据之后,再根据请求的量给Subscriber发数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Override public void request(long n) {
if (n < 0) throw new IllegalArgumentException("n < 0: " + n);
if (n == 0) return; // Nothing to do when requesting 0.
if (!compareAndSet(false, true)) return; // Request was already triggered.

try {
Response<T> response = call.execute();
if (!subscriber.isUnsubscribed()) {
subscriber.onNext(response);
}
} catch (Throwable t) {
Exceptions.throwIfFatal(t);
if (!subscriber.isUnsubscribed()) {
subscriber.onError(t);
}
return;
}

if (!subscriber.isUnsubscribed()) {
subscriber.onCompleted();
}
}

Producerrequest方法中,最主要的就是call.execute(),并把值返回给下游。

总结

Retrofit的分析就这些了,里面的代码确实非常漂亮,非常值得我们去学习。

推荐文章

认真看完这一篇,不懂 Retrofit?不存在的(源码解析
Retrofit分析-漂亮的解耦套路
Retrofit分析-经典设计模式案例
拆轮子系列:拆 Retrofit