一、 前言
本文主要讲Retrofit的原理以及我对这个库设计的理解和看法。写这篇文章的主要目的是加深自己对Retrofit的理解, 同时也希望能够给正在学习Retrofit的同学提供一些帮助。如果有哪里写的不对的地方,欢迎拍砖。
(Ps: 本文源码为retrofit2.9.0)
全文结构如下
- 前言
- Retrofit简介
- Retrofit的核心接口
- Retrofit的原理及运作流程
- 总结
二、 Retrofit简介
(一)、 为什么要Retrofit这个库?
这个库是为了让网络请求的构建以及网络完成后的response处理更加简便。
(二)、 Retrofit是干嘛的?
很多同学会以为Retrofit是一个网络请求库。不对, 它不负责网络请求的执行。这个库的功能主要是
- 简化网络请求的创建
- 处理Response body(如反序列化)
- 灵活处理Response返回类型(如返回Rx的Single)
三、 Retrofit的接口设计
先看retrofit工程的目录结构
- Call接口
- CallAdapter接口
- Callback接口
- Converter接口
(一)、 Call接口
思考两个问题
- 这个接口是干嘛的?
- 如果让你设计这个接口你怎么设计?
- 先讲讲我的想法, Call接口是用来表述一个网络请求任务的, 是一个task。 如果我设计这个接口的话, 我会提供以下方法
//同步执行请求, 直接返回response
fun execute(request: Request): Response
//同步执行请求,回调返回response
fun executeAsync(request: Request, callback: (response: Response)-> Unit)
//取消请求
fun cancel()
- 思考过后, 我们再看看他的源码
/**
* 这是一个retrofit的方法调用, 能够发送请求并且返回响应。
*
* @param <T> 响应成功的response body 类型
*/
public interface Call<T> extends Cloneable {
/**
* 同步发送请求
*/
Response<T> execute() throws IOException;
/**
* 异步发送请求
*/
void enqueue(Callback<T> callback);
/**
* 请求是否已经执行过execute或者enqueue
*/
boolean isExecuted();
/**
* 取消请求
*/
void cancel();
/** True if {@link #cancel()} was called. */
boolean isCanceled();
/** 拷贝 */
Call<T> clone();
/** 返回请求request */
Request request();
/**
* Returns a timeout that spans the entire call: resolving DNS, connecting, writing the request
* body, server processing, and reading the response body. If the call requires redirects or
* retries all must complete within one timeout period.
*/
Timeout timeout();
}
可以看到, 和我的想法基本一致。 不过这里有个很奇怪的点, 大家看request方法, 这个方法的返回值Request是okhttp库里的Request,这说明retrofit库直接引用了okhttp库。
个人觉得这个可以算Retrofit的设计缺陷。如果是我设计的话, 我肯定会在自己库里自己定义request数据结构,再提供一个转换接口暴露给app层。假设我只想用retrofit库而不想用okhttp库, 那么retrofit目前的设计就失去了这种灵活性。 不知道大家有什么看法。
(二)、 CallAdapter接口
同样, 思考两个问题
- 这个接口是干嘛的?
- 如果让你设计这个接口你怎么设计?
- 这个接口是用来把
Response<T>转成我们需要的类型, 比如Single<T>或者其他。 如果我设计这个接口的话, 我会提供以下方法
fun adapterCall(call: Call<T>): R<T>
- 现在我们看他源码
/**
* Adapts a {@link Call} with response type {@code R} into the type of {@code T}. Instances are
* created by {@linkplain Factory a factory} which is {@linkplain
* Retrofit.Builder#addCallAdapterFactory(Factory) installed} into the {@link Retrofit} instance.
*/
public interface CallAdapter<R, T> {
/**
* 最终客户端需要的返回responsebody数据类型
* 如:
* @GET("v1/test")
* fun test(): Single<User>
* 这个接口, 那么此时的responseType返回的就是User
*/
Type responseType();
/**
* 大概就是把retrofit的Call<T>转成一个新的Call<T>(比如okhttp的Call),看了注释里面的sample应该都能看的明白
* Returns an instance of {@code T} which delegates to {@code call}.
*
* <p>For example, given an instance for a hypothetical utility, {@code Async}, this instance
* would return a new {@code Async<R>} which invoked {@code call} when run.
*
* <pre><code>
* @Override
* public <R> Async<R> adapt(final Call<R> call) {
* return Async.create(new Callable<Response<R>>() {
* @Override
* public Response<R> call() throws Exception {
* return call.execute();
* }
* });
* }
* </code></pre>
*/
T adapt(Call<R> call);
/**
* CallAdapter创建工厂
*/
abstract class Factory {
/**
* 比如接口声明的方法是
* @GET("v1/test")
* fun test(): Single<User>
* 那么这个方法就会返回CallAdapter<User, Single<User>>
*/
public abstract @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit);
/**
* 获取泛型参数, Single<User>, 返回User
*/
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}
/**
* 获取泛型前面的那个类型, 如Single<User>, 返回Single
*/
protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
}
(三)、 Callback接口
这个接口很简单, 就是一个请求回调的接口, 不细说了, 直接贴代码
/**
* Communicates responses from a server or offline requests. One and only one method will be invoked
* in response to a given request.
*
* <p>Callback methods are executed using the {@link Retrofit} callback executor. When none is
* specified, the following defaults are used:
*
* <ul>
* <li>Android: Callbacks are executed on the application's main (UI) thread.
* <li>JVM: Callbacks are executed on the background thread which performed the request.
* </ul>
*
* @param <T> Successful response body type.
*/
public interface Callback<T> {
/**
* Invoked for a received HTTP response.
*
* <p>Note: An HTTP response may still indicate an application-level failure such as a 404 or 500.
* Call {@link Response#isSuccessful()} to determine if the response indicates success.
*/
void onResponse(Call<T> call, Response<T> response);
/**
* Invoked when a network exception occurred talking to the server or when an unexpected exception
* occurred creating the request or processing the response.
*/
void onFailure(Call<T> call, Throwable t);
}
唯一需要注意的地方是, 如果没有特别声明, 此回调会在主线程执行(至于为什么, 下面的流程分析会讲到)
(四)、 Converter接口
老规矩, 思考两个问题
- 这个接口是干嘛的?
- 如果让你设计这个接口你怎么设计?
这个接口是用来做类型转换的。我先说说我的想法, 因为retrofit构建好的Request是retrofit自己定义的request, 直接传给网络请求库他不认识, 所以需要一个把retrofit的request转成网络请求库认识的requestBody。同时, 网络请求库返回的response也需要转成客户端需要的数据类型。 所以这个接口如果让我设计, 它大概长这样
//retrofit的request转成实际网络请求执行时候需要的Request, 如retrofit的request转成Okhttp的Request
fun convertRequest(request: Request): T
//把网络请求执行返回的ResponseBody转成客户端需要的数据类型,如Okhttp的ResponseBody转成客户端定义的User
fun convertResponse(responseBody: R): S
好,现在看它源码
/**
* Convert objects to and from their representation in HTTP. Instances are created by {@linkplain
* Factory a factory} which is {@linkplain Retrofit.Builder#addConverterFactory(Factory) installed}
* into the {@link Retrofit} instance.
*/
public interface Converter<F, T> {
/** 很简单, 就是把输入的F转成输出的T。 */
@Nullable
T convert(F value) throws IOException;
/** 创建工厂 */
abstract class Factory {
/**
* 返回一个convert对象,
* 这个convert可以把输出ResponseBody转成Type。这个Type是由CallAdapter的responseType()方法
* 的返回值决定的。
*/
public @Nullable Converter<ResponseBody, ?> responseBodyConverter(
Type type, Annotation[] annotations, Retrofit retrofit) {
return null;
}
/**
* 返回一个convert对象, 这个convert可以把输入Type转成RequestBody。
* 这个的Type通常是从@Body、@Part或者@PartMap得到。
*/
public @Nullable Converter<?, RequestBody> requestBodyConverter(
Type type,
Annotation[] parameterAnnotations,
Annotation[] methodAnnotations,
Retrofit retrofit) {
return null;
}
/**
* 返回一个convert对象, 这个convert可以把输入Type转成String。
* 这个的Type通常是从@Field、@FieldMap、@Header、@HeaderMap、@Path、@Query或者@QueryMap
* 得到。
*/
public @Nullable Converter<?, String> stringConverter(
Type type, Annotation[] annotations, Retrofit retrofit) {
return null;
}
/**
* 获取泛型参数, Single<User>, 返回User
*/
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}
/**
* 获取泛型前面的那个类型, 如Single<User>, 返回Single
*/
protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
}
可以看到和我设想的样子相差甚远。retrofit设计的Converter接口职责拆的更细更单一, 构建起来更优雅。不过这个接口同样有我上文提到的强依赖okhttp库的问题。
四、 Retrofit的原理及流程
通常开发中retrofit会和okhttp、RxJava一起使用, 所以我先按照这三个库一起使用写一个简单的例子。
示例代码
interface SampleApi {
@POST("sample/wakaka")
fun updateUserInfo(@Body param: @JvmSuppressWildcards Map<String, Any>): Single<BaseBean<User>>
}
val okHttpClient : OkHttpClient // okhttp相关细节不在本文讲述
//第一步
val retrofit = Retrofit.Builder()
.baseUrl("https://api.github.com/")
.callFactory(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
//第二步
val sampleApi = retrofit.create(SampleApi::class.java)
//第三步
val singleTask = sampleApi.updateUserInfo(paramsMap)
下面的流程分析都会根据这个示例代码进行分析
第一步, 构建retrofit
Builder模式构建retrofit, 基本都是一些赋值的操作。 唯一需要注意的地方是Retrofit.Builder()这个方法
public final class Retrofit {
...
public static final class Builder {
...
public Builder() {
this(Platform.get()); //Platform.get()会在安卓中会返回Android这个对象
}
}
}
我们看看Android这个对象
static class Android extends Platform {
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@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) {
handler.post(r);
}
}
}
所以retrofit如果没有手动配置过callbackExecutor的话, 默认Callback会在主线程执行。 ( Handler和Looper相关的内容也不在这篇文章赘述了, 做安卓应该都知道 )
第二步, 动态代理实现网络接口的实现
如示例代码中的SampleApi, 他是一个接口, 如果想要他是可执行的类, 我们通常的做法是声明一个类继承它, 然后在里面处理它的具体实现。我们来看看retrofit他是怎么设计
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() {
//就是上文讲过的Android
private final Platform platform = Platform.get();
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
//如果是Object自己的方法, 就直接调用了, 如toString(), hashCode()等等
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//Android的isDefaultMethod方法恒返回false, 所以这个方法不用看了
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//step1
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
//step2
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);
}
});
}
哦, retrofit用的是动态代理来实现接口的调用。(动态代理的相关知识不在本文讲述)我们重点来看它的invoke方法。
step1
loadServiceMethod方法, 把method解析成ServiceMethod对象
public final class Retrofit {
private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
ServiceMethod<?, ?> loadServiceMethod(Method method) {
//先从缓存中直接拿ServiceMethod
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
//若缓存中有, 则直接返回
if (result != null) return result;
//虽然用的ConcurrentHashMap, 但是复合操作还是不能保证原子性, 所以这里用synchronized上锁
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
//若缓存没有, 则创建一个ServiceMethod, 并把它加入缓存
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
}
按照示例代码走, new ServiceMethod.Builder<>(this, method).build()这个build方法会创建出
RxJava2CallAdapter<Object, Object>, GsonResponseBodyConverter<BaseBean<User>>, GsonRequestBodyConverter<Map>, 最后创建出ServiceMethod对象。
此处我有一个优化想法,
loadServiceMethod方法是中通过key从缓存取value, 若value不存在则新建对象并添加到缓存中。 retrofit用的是synchronize悲观锁锁住了这一段代码, 那么此处是否可以优化改用乐观锁呢?看到这种需求我首先想到的是ConcurrentHashMap的putIfAbsent方法。 但是putIfAbsent这个方法需要直接传value, 而我们的value构建是耗时的。 我们的需求是先判断不存在, 再创建实例,再put, 并且要保证这三个步骤的原子性。 我的想法是, 改造一下ConcurrentHashMap, 新加一个putIfAbsentByLazyInit方法,不过最后我却发现这个思路似乎不可行, 因为最终compareAndSwapObject还是需要传入具体的value, 因此我的想法是错误的。。。不知道大家有没有什么想法, 欢迎分享。
class MyConcurrentHashMap<K, V> : ConcurrentHashMap<K,V>{
fun putIfAbsentByLazyInit(K key, factory: DataFactory<V>) {
...
}
interface DataFactory<V> {
fun get(): V
}
}
step2
构建OkHttpCall, 然后调用RxJava2CallAdapter的adapter方法, 输入的参数是OkHttpCall。
final class RxJava2CallAdapter<R> implements CallAdapter<R, Object> {
@Override public Object adapt(Call<R> call) {
//RxJava2CallAdapterFactory.create()构建的, isAsync为false
Observable<Response<R>> responseObservable = isAsync
? new CallEnqueueObservable<>(call)
: new CallExecuteObservable<>(call);
Observable<?> observable;
if (isResult) {
observable = new ResultObservable<>(responseObservable);
} else if (isBody) { //此示例中isBody为true
observable = new BodyObservable<>(responseObservable);
} else {
observable = responseObservable;
}
if (scheduler != null) {
observable = observable.subscribeOn(scheduler);
}
if (isFlowable) {
return observable.toFlowable(BackpressureStrategy.LATEST);
}
if (isSingle) { //此示例中isSingle为true
return observable.singleOrError();
}
if (isMaybe) {
return observable.singleElement();
}
if (isCompletable) {
return observable.ignoreElements();
}
return observable;
}
}
大概流程
先创建CallExecuteObservable, 在创建BodyObservable把CallExecuteObservable包了一层, 有点代理的意思, 但不完全正确, 最后在根据接口定义好的Rx流转成与之匹配的Rx流, 本示例中是Single。
下面看看这两个Observable是怎么实现的吧。
final class CallExecuteObservable<T> extends Observable<Response<T>> {
private final Call<T> originalCall;
CallExecuteObservable(Call<T> originalCall) {
this.originalCall = originalCall;
}
@Override protected void subscribeActual(Observer<? super Response<T>> observer) {
// Since Call is a one-shot type, clone it for each new observer.
Call<T> call = originalCall.clone();
//负责控制任务发射
CallDisposable disposable = new CallDisposable(call);
observer.onSubscribe(disposable);
boolean terminated = false;
try {
Response<T> response = call.execute();
if (!disposable.isDisposed()) {
observer.onNext(response);
}
if (!disposable.isDisposed()) {
terminated = true;
observer.onComplete();
}
} catch (Throwable t) {
Exceptions.throwIfFatal(t);
if (terminated) {
RxJavaPlugins.onError(t);
} else if (!disposable.isDisposed()) {
try {
observer.onError(t);
} catch (Throwable inner) {
Exceptions.throwIfFatal(inner);
RxJavaPlugins.onError(new CompositeException(t, inner));
}
}
}
//怎么感觉这东东有点像阉割版的Emitter啊,可能是Rx1的时候的代码吧, 哈哈。
private static final class CallDisposable implements Disposable {
private final Call<?> call;
private volatile boolean disposed;
CallDisposable(Call<?> call) {
this.call = call;
}
@Override public void dispose() {
disposed = true;
call.cancel();
}
@Override public boolean isDisposed() {
return disposed;
}
}
}
}
这个类就是在Observable的subscribeActual时候, 执行call.execute(), 再把它发到Observer。按照示例代码, 就是把Call<BaseBean>转成Single<Response<BaseBean>>。
BodyObservable这个类代码就不贴了, 很简单, 就是把Single<Response<BaseBean>>转成Single<BaseBean>。
总结
这张图完美的诠释了Retrofit的整个流程图
Ps: 图片来自网络