从使用方法出发,首先是怎么使用,其次是咱们使用的功能在内部是如何实现的, 实现方案上有什么技巧,有什么范式。全文基本上是对 Retrofit 源码的一个分析与 导读,很是建议你们下载 Retrofit 源码以后,跟着本文,过一遍源码。java
上图知识汇总的PDF相关内容后续GitHub更新,想冲击金三银四的小伙伴能够找找看看,欢迎star
(顺手留下GitHub连接,须要获取相关面试等内容的能够本身去找)
https://github.com/xiangjiana/Android-MS
(VX:mm14525201314)git
Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/") .addConverterFactory(GsonConverterFactory.create()) .build();
public interface GitHubService { @GET("users/{user}/repos") Call<List<Repo>> listRepos(@Path("user") String user); } GitHubService github = retrofit.create(GitHubService.class);
先看定义,很是简洁,也没有什么特别之处,除了两个注解:@GET
和 @Path
。它们的用处稍后再分析,咱们接着看建立 API 实 例: retrofit.create(GitHubService.class)
。这样就建立了 API 实例了, 就能够调用 API 的方法发起 HTTP 网络请求了,太方便了。 但 create
方法是怎么建立 API 实例的呢?github
public <T> T create(final Class<T> service) { // 省略非关键代码 return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service }, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object ... args) throws Throwable { // 先省略实现 } }); }
建立 API 实例使用的是动态代理技术。 面试
简而言之,就是动态生成接口的实现类(固然生成实现类有缓存机制),并建立其 实例(称之为代理),代理把对接口的调用转发给 InvocationHandler
实例, 而在 InvocationHandler
的实现中,除了执行真正的逻辑(例如再次转发给真 正的实现类对象),咱们还能够进行一些有用的操做,例如统计执行时间、进行初 始化和清理、对接口调用进行检查等。 为何要用动态代理?由于对接口的全部方法的调用都会集中转发到 InvocationHandler#invoke
函数中,咱们能够集中进行处理,更方便了。你可 能会想,我也能够手写这样的代理类,把全部接口的调用都转发到 InvocationHandler#invoke
呀,固然能够,可是可靠地自动生成岂不更方便?编程
获取到 API 实例以后,调用方法和普通的代码没有任何区别:json
Call<List<Repo>> call = github.listRepos("square"); List<Repo> repos = call.execute().body();
这两行代码就发出了 HTTP 请求,并把返回的数据转化为了 List<Repo>
,太方 便了!api
如今咱们来看看调用 listRepos
是怎么发出 HTTP 请求的。上面 Retrofit#create 方法返回时省略的代码以下:缓存
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 n ormal invocation. if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } if (platform.isDefaultMethod(method)) { return platform.invokeDefaultMethod(method, service, p roxy, args); } ServiceMethod serviceMethod = loadServiceMethod(method); OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args); return serviceMethod.callAdapter.adapt(okHttpCall); } });
若是调用的是 Object
的方法,例如 equals
, toString
,那就直接调用。 若是是 default
方法(Java 8 引入),就调用 default
方法。这些咱们都先无论,因 为咱们在安卓平台调用 listRepos
,确定不是这两种状况,那此次调用真正干活 的就是这三行代码了(好好记住这三行代码,由于接下来很长的篇幅都是在讲它们 :) ):服务器
ServiceMethod serviceMethod = loadServiceMethod(method); OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args); return serviceMethod.callAdapter.adapt(okHttpCall);
在继续分析这三行代码以前,先看一个流程图
这三行代码基本就是对应于流程图中轴上部了, ServiceMethod
, build OkHttpCall
, CallAdapter adapt
。网络
ServiceMethod<T>
类的做用正如其 JavaDoc
所言:
Adapts an invocation of an interface method into an HTTP call. 把对接口方法 的调用转为一次 HTTP 调用。
一个 ServiceMethod
对象对应于一个 API interface
的一个方 法, loadServiceMethod(method)
方法负责加载 ServiceMethod
:
ServiceMethod loadServiceMethod(Method method) { ServiceMethod 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
的构造函数:
ServiceMethod(Builder<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; }
成员不少,但这里咱们重点关注四个成 员: callFactory
, callAdapter
, responseConverter
和 parameterHandlers
。
callFactory
负责建立 HTTP 请求,HTTP 请求被抽象为了okhttp3.Call
类,它表示一个已经准备好,能够随时执行的 HTTP 请求;callAdapter
把retrofit2.Call<T>
转为 T (注意和okhttp3.Call
区分开来,retrofit2.Call<T>
表示的是对一个 Retrofit 方法的调用),这个过程会发送一个 HTTP 请求,拿到服务器返回的数据(通 过okhttp3.Call
实现),并把数据转换为声明的 T 类型对象(经过Converter<F, T>
实现);responseConverter
是Converter<ResponseBody, T>
类型,负责把服 务器返回的数据(JSON、XML、二进制或者其余格式,由ResponseBody
封装)转化为 T 类型的对象;parameterHandlers
则负责解析 API 定义时每一个方法的参数,并在构造 HTTP 请求时设置参数;
它们的使用稍后再分析,这里先看看它们的建立(代码比较分散,就不贴太多代码 了,大可能是结论):
callFactory
this.callFactory = builder.retrofit.callFactory()
,因此 callFactory
实际上由 Retrofit 类提供,而咱们在构造 Retrofit 对象 时,能够指定 callFactory
,若是不指定,将默认设置为一个 okhttp3.OkHttpClient
。
callAdapter
private CallAdapter<?> createCallAdapter() { // 省略检查性代码 Annotation[] annotations = method.getAnnotations(); try { return 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 类内部, 将遍历一个 CallAdapter.Factory
列表,让工厂们提供,若是最终没有工厂能 (根据 returnType
和 annotations
)提供须要的 CallAdapter
,那将抛出 异常。而这个工厂列表咱们能够在构造 Retrofit
对象时进行添加。
responseConverter
private Converter<ResponseBody, T> createResponseConverter() { Annotation[] annotations = method.getAnnotations(); try { return retrofit.responseBodyConverter(responseType, annotati ons); } catch (RuntimeException e) { // Wide exception range because factories are user code. throw methodError(e, "Unable to create converter for %s", re sponseType); } }
一样, responseConverter
仍是由 Retrofit 类提供,而在其内部,逻辑和创 建 callAdapter
基本一致,经过遍历 Converter.Factory
列表,看看有没有 工厂可以提供须要的 responseBodyConverter
。工厂列表一样能够在构造 Retrofit 对象时进行添加。
parameterHandlers
每一个参数都会有一个 ParameterHandler
,由 ServiceMethod#parseParameter
方法负责建立,其主要内容就是解析每一个参数 使用的注解类型(诸如 Path , Query , Field
等),对每种类型进行单独的 处理。构造 HTTP 请求时,咱们传递的参数都是字符串,那 Retrofit 是如何把咱们 传递的各类参数都转化为 String 的呢?仍是由 Retrofit 类提供 converter!
Converter.Factory
除了提供上一小节提到的 responseBodyConverter
,还提 供 requestBodyConverter
和 stringConverter
,API 方法中除了 @Body
和 @Part
类型的参数,都利用 stringConverter
进行转换,而 @Body
和 @Part
类型的参数则利用 requestBodyConverter
进行转换。
这三种 converter
都是经过“询问”工厂列表进行提供,而工厂列表咱们能够在构造 Retrofit
对象时进行添加。
上面提到了三种工厂: okhttp3.Call.Factory
, CallAdapter.Factory
和 Converter.Factory
,分别负责提供不一样的模块,至于怎么提供、提供何种模 块,通通交给工厂,Retrofit 彻底不掺和,它只负责提供用于决策的信息,例如参 数/返回值类型、注解等。
这不正是咱们苦苦追求的高内聚低耦合效果吗?解耦的第一步就是面向接口编程, 模块之间、类之间经过接口进行依赖,建立怎样的实例,则交给工厂负责,工厂同 样也是接口,添加(Retrofit doc
中使用 install 安装一词,很是贴切)怎样的工 厂,则在最初构造 Retrofit
对象时决定,各个模块之间彻底解耦,每一个模块只 专一于本身的职责,全都是套路,值得反复玩味、学习与模仿。
除了上面重点分析的这四个成员, ServiceMethod
中还包含了 API 方法的 url 解 析等逻辑,包含了众多关于泛型和反射相关的代码,有相似需求的时候,也很是值 得学习模仿
终于把 ServiceMethod
看了个大概,接下来咱们看看 OkHttpCall
。 OkHttpCall
实现了 retrofit2.Call
,咱们一般会使用它的 execute()
和 enqueue(Callback<T> callback)
接口。前者用于同步执行 HTTP 请求,后者 用于异步执行。
execute()
@Override public Response<T> execute() throws IOException { okhttp3.Call call; synchronized (this) { // 省略部分检查代码 call = rawCall; if (call == null) { try { call = rawCall = createRawCall(); } catch (IOException | RuntimeException e) { creationFailure = e; throw e; } } } return parseResponse(call.execute()); ...... }
主要包括三步:
- 建立
okhttp3.Call
,包括构造参数;- 执行网络请求;
- 解析网络请求返回的数据;
createRawCall()
函数中,咱们调用了 serviceMethod.toRequest(args)
来建立 okhttp3.Request
,而在后者中,咱们以前准备好的 parameterHandlers
就派上了用场。
而后咱们再调用 serviceMethod.callFactory.newCall(request)
来建立 okhttp3.Call
,这里以前准备好的 callFactory
一样也派上了用场,因为工 厂在构造 Retrofit 对象时能够指定,因此咱们也能够指定其余的工厂(例如使 用过期的 HttpURLConnection
的工厂),来使用其它的底层 HttpClient
实现。
咱们调用 okhttp3.Call#execute()
来执行网络请求,这个方法是阻塞的,执行 完毕以后将返回收到的响应数据。收到响应数据以后,咱们进行了状态码的检查, 经过检查以后咱们调用了 serviceMethod.toResponse(catchingBody)
来把响 应数据转化为了咱们须要的数据类型对象。在 toResponse
函数中,咱们以前准 备好的 responseConverter
也派上了用场。
好了,以前准备好的东西都派上了用场,还好没有白费 :)
enqueue(Callback<T> callback)
这里的异步交给了 okhttp3.Call#enqueue(Callback responseCallback)
来 实现,并在它的 callback
中调用 parseResponse
解析响应数据,并转发给传入 的 callback
。
CallAdapter
终于到了最后一步了, CallAdapter<T>#adapt(Call<R> call)
函数负责把 retrofit2.Call<R>
转为 T 。这里 T 固然能够就是 retrofit2.Call<R>
,这时咱们直接返回参数就能够了,实际上这正是 DefaultCallAdapterFactory
建立的 CallAdapter
的行为。至于其余类型的 工厂返回的 CallAdapter
的行为,这里暂且不表,后面再单独分析。
至此,一次对 API 方法的调用是如何构造并发起网络请求、以及解析返回数据,这 整个过程大体是分析完毕了。对整个流程的概览很是重要,结合 stay 画的流程图, 应该可以比较轻松地看清整个流程了。
虽然咱们还没分析完,不过也至关于到了万里长征的遵义,终于能够舒一口气了 :)
retrofit 模块内置了 DefaultCallAdapterFactory
和 ExecutorCallAdapterFactory
,它们都适用于 API 方法获得的类型为 retrofit2.Call
的情形,前者生产的 adapter 啥也不作,直接把参数返回,后 者生产的 adapter 则会在异步调用时在指定的 Executor 上执行回调。
retrofit-adapters
的各个子模块则实现了更多的工 厂: GuavaCallAdapterFactory
, Java8CallAdapterFactory
和 RxJavaCallAdapterFactory
。这里我主要分析 RxJavaCallAdapterFactory
,下面的内容就须要一些 RxJava
的知识了,不过 我想使用 Retrofit 的你,确定也在使用RxJava
:)
RxJavaCallAdapterFactory#get
方法中对返回值的类型进行了检查,只支持 rx.Single
, rx.Completable
和 rx.Observable
,这里我主要关注对 rx.Observable
的支持。
RxJavaCallAdapterFactory#getCallAdapter
方法中对返回值的泛型类型进行 了进一步检查,例如咱们声明的返回值类型为 Observable<List<Repo>>
,泛型 类型就是 List<Repo>
,这里对 retrofit2.Response
和retrofit2.adapter.rxjava.Result
进行了特殊处理,有单独的 adapter 负责 进行转换,其余全部类型都由 SimpleCallAdapter
负责转换。
那咱们就来看看 SimpleCallAdapter#adapt
:
@Override public <R> Observable<R> adapt(Call<R> call) { Observable<R> observable = Observable.create(new CallOnSubscri be<>(call)) .lift(OperatorMapResponseToBodyOrError.<R>instance()); if (scheduler != null) { return observable.subscribeOn(scheduler); } return observable; }
这里建立了一个 Observable
,它的逻辑由 CallOnSubscribe
类实现,同时使 用了一个 OperatorMapResponseToBodyOrError
操做符,用来把 retrofit2.Response
转为咱们声明的类型,或者错误异常类型。
咱们接着看 CallOnSubscribe#call
:
@Override public void call(final Subscriber<? super Response<T>> subscribe r) { // Since Call is a one-shot type, clone it for each new subscr iber. 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(requestArbiter); subscriber.setProducer(requestArbiter); }
代码很简短,只干了三件事:
- clone 了原来的 call,由于
okhttp3.Call
是只能用一次的,因此每次都是 新 clone 一个进行网络请求;- 建立了一个叫作
RequestArbiter
的producer
,别被它的名字吓懵了,它就 是个producer
;- 把这个
producer
设置给subscriber
;
简言之,大部分状况下 Subscriber
都是被动接受 Observable push
过来的数据, 但要是 Observable
发得太快,Subscriber
处理不过来,那就有问题了,因此就有 了一种 Subscriber
主动 pull
的机制,而这种机制就是经过 Producer
实现的。给 Subscriber
设置 Producer
以后(经过 Subscriber#setProducer
方法), Subscriber
就会经过 Producer 向上游根据本身的能力请求数据(经过 Producer#request
方法),而 Producer
收到请求以后(一般都是 Observable
管理 Producer
,因此“至关于”就是 Observable
收到了请求),再根据请求的量给 Subscriber 发数据。
那咱们就看看 RequestArbiter#request
:
@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 alread y 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(); } }
producer
相关的逻辑很是简单,这里就不在赘述。实际干活的逻辑就是执行 call.execute()
,并把返回值发送给下游。
而 OperatorMapResponseToBodyOrError#call
也至关简短:
@Override public Subscriber<? super Response<T>> call(final Subscriber<? s uper T> child) { return new Subscriber<Response<T>>(child) { @Override public void onNext(Response<T> response) { if (response.isSuccessful()) { child.onNext(response.body()); } else { child.onError(new HttpException(response)); } } @Override public void onCompleted() { child.onCompleted(); } @Override public void onError(Throwable e) { child.onError(e); } }; }
关键就是调用了 response.body()
并发送给下游。这里, body()
返回的就是 咱们声明的泛型类型了,至于 Retrofit
是怎么把服务器返回的数据转为咱们声明的 类型的,这就是 responseConverter
的事了,还记得吗?
最后看一张返回 Observable
时的调用栈:
执行路径就是:
Observable.subscribe
,触发 API 调用的执行;CallOnSubscribe#call
,clone call
,建立并设置producer
;RequestArbiter#request
,subscriber
被设置了producer
以后最终调用 request,在 request 中发起请求,把结果发给下游;OperatorMapResponseToBodyOrError$1#onNext
,把response
的 body 发 给下游;- 最终就到了咱们
subscribe
时传入的回调里面了;
retrofit 模块内置了 BuiltInConverters
,只能处理 ResponseBody
, RequestBody
和 String 类型的转化(实际上不须要转)。而 retrofit- converters 中的子模块则提供了 JSON
,XML
,ProtoBuf
等类型数据的转换功能, 并且还有多种转换方式能够选择。这里我主要关注 GsonConverterFactory
。
代码很是简单:
@Override public Converter<ResponseBody, ?> responseBodyConverter(Type typ e, Annotation[] annotations, Retrofit retrofit) { TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type)); return new GsonResponseBodyConverter<>(gson, adapter); } final class GsonResponseBodyConverter<T> implements Converter<Re sponseBody, T> { private final Gson gson; private final TypeAdapter<T> adapter; GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) { this.gson = gson; this.adapter = adapter; } @Override public T convert(ResponseBody value) throws IOExcept ion { JsonReader jsonReader = gson.newJsonReader(value.charStream( )); try { return adapter.read(jsonReader); } finally { value.close(); } } }
根据目标类型,利用 Gson#getAdapter
获取相应的 adapter,转换时利用 Gson
的 API 便可。
上图知识汇总的PDF相关内容后续GitHub更新,想冲击金三银四的小伙伴能够找找看看,欢迎star
(顺手留下GitHub连接,须要获取相关面试等内容的能够本身去找)
https://github.com/xiangjiana/Android-MS
(VX:mm14525201314)