Retrofit 源码深度解析-(3)Invoke
2.4 ServiceMethod#invoke
2.4.1 时序图
invoke
的第一步,是执行CallAdapted#invoke
,通过上面的UML图分析,可以知道在HttpServiceMethod
实现了ServiceMethod
的invoke
@Override
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
首先 new了一个OkHttpCall
,随后转到了ServiceMethod#adapt
方法。
进入adapt
:
@Override
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return callAdapter.adapt(call);
}
内部转到了CallAdapter
处理请求。
从上面的流程,可以看到,作为继承自ServiceMethod的CallAdapted
来说,主要工作有两个:1)构建OkHttpCall
,2)将OkHttpCall
实例传入适配器进行处理。
同时,由CallAdapted
的处理思路以及命名,也大概明白CallAdapted属
于ServiceMethod
与CallAdapter
的桥梁。
好了,现在来到CallAdapter
。
2.4.2 CallAdapter
单单看CallAdapter
的定义:
/**
* 将响应类型为R的Call调整为T的类型
*/
public interface CallAdapter<R, T> {
/**
* 返回此适配器在将HTTP响应主体转换为Java对象时使用的值类型。例如,Call<Repo>的响应类型是Repo。
此类型用于准备传递给#adapt的调用。
注意:这通常与提供给此调用适配器工厂的returnType不同。
*/
Type responseType();
/**
* 返回一个委托调用的T实例。
例如,给定一个假设的实用程序Async的实例,该实例将返回一个新的Async<R>,该Async在运行时调用。
@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();
}
});
}
*/
T adapt(Call<R> call);
}
可以得知,该组件是用于通过将Call\<R\>
的R
进行转换,从而得到一个T
类型的实例。而R类型,在创建CallAdapter
时由工厂代码的get方法所接收。
同时responseType
方法在上面parseAnnotations
有讲到,是用来确定responseConvert
的。
可能看注释不太能理解CallAdapter
组件的存在意义,可以通过看Retroft
提供的几个CallAdapter
的实现类,来窥探出CallAdapter
组件的职责。
忽略两个测试类,可以看到,Retrofit
默认提供了三个实现类:DefaultCallAdapterFactory#anonymousClass
、BodyCallAdapter
和ResponseCallAdapter
。
这两个类可能没印象了,这里回顾一下Retrofit.Build#build
的代码:
// Retrofit.Build#build代码片段
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
// Platform#defaultCallAdapterFactories 方法
List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
@Nullable Executor callbackExecutor) {
DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
return hasJava8Types
? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
: singletonList(executorFactory);
}
可以看到,在Hotspot平台下,默认会有两个CallAdapterFactory
:DefaultCallAdapterFactory
和CompletableFutureCallAdapterFactory
。而上面三个CallAdapter
实现类,就是通过这两个工厂类构建出来的,接下来进行一一分析。
2.4.2.1 DefaultCallAdapterFactory#anonymousClass
由于这个工厂提供的CallAdapter
是一个匿名内部类,所以为了更好的理解,这里DefaultCallAdapterFactory#get
将代码贴出来
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
// 只支持方法返回值为Call类型的方法
return null;
} else if (!(returnType instanceof ParameterizedType)) {
// 必须指定Call的形参类型
throw new IllegalArgumentException("Call return type must be parameterized as Call<Foo> or Call<? extends Foo>");
} else {
// 获取Call<String>的String类型
final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType)returnType);
// 方法是否包含@SkipCallbackExecutor注解
final Executor executor = Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class) ? null : this.callbackExecutor;
// 创建一个匿名内部类
return new CallAdapter<Object, Call<?>>() {
// 如果方法返回值是Call<String> 那么这里返回的type就是String,通过这个类型 来指定responseConvert类型
// 同时 这个类型也定义了adapt方法参数Call的形参参数类型
public Type responseType() {
return responseType;
}
public Call<Object> adapt(Call<Object> call) {
// 这里的executor的设置,来源于Retrofit.Build#build时,添加的基于platform的执行器
// 如果是Hotspot平台,则这个方法将参数的call直接返回了
// 其实通过DefaultCallAdapterFactory#get方法的校验流程,也可以知道,当前Convert的返回值是Call类型
return (Call)(executor == null ? call : new DefaultCallAdapterFactory.ExecutorCallbackCall(executor, call));
}
};
}
}
通过get方法return之前的代码可以明确的是当前CallAdapter#adapt
方法返回的是Call
类型,也就需要Service方法的返回类型是Call,例如:
public interface BaiduApi {
@GET("/")
Call<String> get1(@Query("aaa") String args);
}
这种是支持的。同时由于adapt方法的入参既Call
,所以方法直接将Call
返回。(不考虑Android的平台)
可能一个CallAdapter
还不能整理出规则,继续看Retrofit
提供的下一个CallAdapter
。
2.4.2.2 BodyCallAdapter
BodyCallAdapter
是由CompletableFutureCallAdapterFactory
进行构建的,查看构建的代码:
// CompletableFutureCallAdapterFactory#get 代码片段
if (getRawType(returnType) != CompletableFuture.class) {
// 只关心方法返回值为CompletableFuture类型的方法
return null;
}
if (getRawType(innerType) != Response.class) {
// 如果方法返回值是CompletableFuture<String或者其他具体类型> 的 返回BodyCallAdapter
// Generic type is not Response<T>. Use it for body-only adapter.
return new BodyCallAdapter<>(innerType);
}
通过最上面的returnType
的校验,可以得知CompletableFutureCallAdapterFactory
是针对方法返回值为java8的CompletableFuture
类型所提供CallAdapter
的。
所以继续查看BodyCallAdapter
:
private static final class BodyCallAdapter<R> implements CallAdapter<R, CompletableFuture<R>> {
// 移除了responseType相关定义
@Override
public CompletableFuture<R> adapt(final Call<R> call) {
// new 了一个CallCancelCompletableFuture
CompletableFuture<R> future = new CallCancelCompletableFuture<>(call);
// new 了一个BodyCallback
call.enqueue(new BodyCallback(future));
return future;
}
}
adapt
方法内部有引出了两个关键的类:CallCancelCompletableFuture
和BodyCallback
。
其中CallCancelCompletableFuture
继承了CompletableFuture
,定义了一个Call
类型的构造函数,同时重写了cancel
方法:
private static final class CallCancelCompletableFuture<T> extends CompletableFuture<T> {
// 隐去构造函数等代码
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
if (mayInterruptIfRunning) {
// 执行Call cancel
call.cancel();
}
return super.cancel(mayInterruptIfRunning);
}
}
而而BodyCallback
则实现了Callback
:
private class BodyCallback implements Callback<R> {
private final CompletableFuture<R> future;
// 通过构造函数传入CompletableFuture
public BodyCallback(CompletableFuture<R> future) {
this.future = future;
}
@Override
public void onResponse(Call<R> call, Response<R> response) {
if (response.isSuccessful()) {
// 成功 则调用CompletableFuture#complete
future.complete(response.body());
} else {
future.completeExceptionally(new HttpException(response));
}
}
@Override
public void onFailure(Call<R> call, Throwable t) {
// 失败调用
future.completeExceptionally(t);
}
}
通过上面的代码,大概明白了BodyCallAdapter
组件的用处:
通过对返回值类型为
CompletableFuture<Response<具体类型>>
的适配。
举个例子:
@GET("/")
CompletableFuture<String> get26();
则调用方:
CompletableFuture<String> responseCompletableFuture = retrofit.create(BaiduApi.class).get26();
// 获取异步结果
String stringResponse = responseCompletableFuture.get();
// 或者 有限时间获取
responseCompletableFuture.get(1, TimeUnit.SECONDS);
可以达到发起请求为异步的效果。
2.4.2.3 ResponseCallAdapter
这个同BodyCallAdapter
差不大多,区别在于ResponseCallAdapter
适配的是方法返回值为CompletableFuture<Response<String>或者其他类型>
而BodyCallAdapter
则为其他泛型。
2.4.2.4 CallAdapter总结
通过对三款默认的CallAdapter
的代码定义,以及场景分析,由此我们可以知道,CallAdapter
是针对方法的具体业务返回值之上的一层包装适配。
例如,如果业务返回的对象为Data
,但同时在一些特殊场景下,例如异步,则可以将结果包装成CompletableFuture<Data>
,或者使用RxJava
。可以达到异步和回调的效果。
这个部分同ResponseConvert
有一些些许的概念冲突,因为ResponseConver
的定义是将Http返回结果给转换成需要的对象,当前对象是业务对象,而CallAdapter则在业务对线之上提供一个扩展,可以以不同的方式来接入。
实际场景:异步、回调、
或者通过查看retrofit-adapters目录:
基本都是对现在比较主流的异步框架进行适配。
介绍完CallAdapter
之后,继续回到调用流程当中。由于CallAdapter
有多个实现,但其实思路都差不多,这里使用DefaultCallAdapterFactory#anonymousClass
来进行流程梳理:
public Call<Object> adapt(Call<Object> call) {
return (Call)(executor == null ? call : new DefaultCallAdapterFactory.ExecutorCallbackCall(executor, call));
}
可以看到,DefaultCallAdapterFactory#anonymousClass
只是简单的将call
进行返回。所以回忆一下我们的使用:
public interface BaiduApi {
@GET("/")
Call<String> get1(@Query("aaa") String args);
}
// 调用
Call<String> api = retrofit.create(BaiduApi.class).get1("");
// 真正执行
Response<String> stringResponse = api.execute();
所以下一个流程,就在api.execute()
当中
2.5 execute
2.51 时序图
2.5.2 Retrofit2.Call
要理清Call#execute
方法的内部实现,就需要先Retrofit2.Call
的定义。
先看类的定义:
乍一看没什么特殊的,但用过okhttp
的同学可能有点印象,那么,继续看看okhttp3.Call
的定义:
可以看到,不能说是毫无关系,只能说是基本一样。实际上,Retrofit2.Call
就是对okhttp3.Call
的包装,在其基础之上,通过ResponseConvert
将返回结果包装成对应的返回对象。
看看官方对Retrofit2.Call
的定义:
An invocation of a Retrofit method that sends a request to a webserver and returns a response. Each call yields its own HTTP request and response pair. Use clone to make multiple calls with the same parameters to the same webserver; this may be used to implement polling or to retry a failed call.
Calls may be executed synchronously with execute, or asynchronously with enqueue. In either case the call can be canceled at any time with cancel. A call that is busy writing its request or reading its response may receive a IOException; this is working as designed.对Retrofit方法的调用,该方法向web服务器发送请求并返回响应。每个调用都会产生自己的HTTP请求和响应对。使用clone()对同一个web服务器进行多次调用,使用相同的参数;这可用于实现轮询或重试失败的调用。
调用可以通过execute同步执行,也可以通过enqueue异步执行。在这两种情况下,call都可以在任何时候用cancel来取消。一个正在写请求或读取响应的调用可能会收到IOException;这是设计好的。
通过定义大概明白了Retrofit2.Call
的角色:Retrofit
Service
方法调用的抽象。同时还得知了Retrofit2.Call
的一些特性:可异步化、取消、通过clone()
方法进行请求复制达到重试的机制等等。
同时,伴随着Retrofit2.Call
的,还有一个特殊组件:retrofit2.Callback
同Retrofit2.Call
一样,改组件是为了适配okhttp3.Callback
:
在了解了Retrofit2.Call
的定义之后,继续深入到内部实现。通过查看Retrofit2.Call
的实现类:
2.5.2.1 OkHttpCall
不知道大家对这个类还有没有印象,在HTTPServiceMethod#invoke
方法中,new了一个OkHttpCall
实例:
@Override
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
默认情况下,OkHttpCall
就是我们调用时的Call
实现,所以,通过OkHttpCall
,就可以知道核心的http请求流程,retrofit是如何整合okhttp3
的。
先看一下OkHttpCall
的UML图:
可以看到,在OkhttpCall
的属性当中,关键的几个属性requestFactory
, args
, callFactory
, responseConverter
,是通过构造函数传入的,分别是:构建请求参数的工厂,调用方法传入的参数,okhttp
的Call
实例和返回结果的转换器。
接下来通过解析execute
方法内部的实现,来一探究竟。
2.5.2.1.1 OkhttpCall#execute
先看一下代码:
@Override
public Response<T> execute() throws IOException {
okhttp3.Call call;
// 一个Call只可以被调用一次,避免并发
synchronized (this)
// 使用executed标志位记录执行状态
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
// 获取到一个okhttp3.Call实例
call = getRawCall();
}
// 在真正执行前,先判断是否被调用了retrofit.Call#cancel 则中断调用
// canceled是一个被volatile修饰过的
if (canceled) {
call.cancel();
}
// 执行okhttp3.Call#execute并将返回结果转换
return parseResponse(call.execute());
}
可以看到,整个代码思路还是很清晰的,加锁避免重复调用,构建 okhttp3.Call
实例,执行 okhttp3.Call#execute
方法,转换返回数据。下面对每个关键步骤进行一一解析。
2.5.2.1.2 OkhttpCall#getRawCall
通过该方法的定义,就可以知道这个方法是返回一个原始的okhttp3.Call
实例的。
private okhttp3.Call getRawCall() throws IOException {
okhttp3.Call call = rawCall;
if (call != null) return call;
// 抛出上一次创建的异常,因为有可能是多次调用
if (creationFailure != null) {
if (creationFailure instanceof IOException) {
throw (IOException) creationFailure;
} else if (creationFailure instanceof RuntimeException) {
throw (RuntimeException) creationFailure;
} else {
throw (Error) creationFailure;
}
}
// 创建 并记录成功或者失败
try {
return rawCall = createRawCall();
} catch (RuntimeException | Error | IOException e) {
// 这个方法内部针对一些致命错误进行了抛出 例如虚拟机异常等等
throwIfFatal(e); // 不要给creationFailure分配致命错误。
creationFailure = e;
throw e;
}
}
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
首先判断了属性creationFailure
是否不为空,如果不为空则抛出。这个判断是为了避免在重复调用Call
时,上一次失败的情况下,就直接抛出了。
随后,转入createRawCall
方法真正执行创建。熟悉okhttp
的同学应该对这个代码比较熟悉,使用facotry
传入okhttp3.Request
后new 一个call
。
其中最核心的,最需要关注的,是RequestFactory#create
。
好了,还记得之前在ServiceMethod#parseAnnotations
方法,构造出来的RequestFactory
吗?现在就用上了。
okhttp3.Request create(Object[] args) throws IOException {
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
int argumentCount = args.length;
if (argumentCount != handlers.length) {
// 抛出异常 参数数量匹配不上
}
// 构建RequestBuilder实例
RequestBuilder requestBuilder =
new RequestBuilder(
httpMethod,
baseUrl,
relativeUrl,
headers,
contentType,
hasBody,
isFormEncoded,
isMultipart);
List<Object> argumentList = new ArrayList<>(argumentCount);
for (int p = 0; p < argumentCount; p++) {
argumentList.add(args[p]);
// 迭代handlers,调用对应的apply方法
handlers[p].apply(requestBuilder, args[p]);
}
// 得到Request.Builder实例,打上tag,再调用build方法构建Request
return requestBuilder.get().tag(Invocation.class, new Invocation(method, argumentList)).build();
}
RequestFactory#create
方法的目的,是创建一个okhttp3.Request
实例。
内部先是构建了一个RequestBuilder
实例,然后通过RequestBuilder#get
得到okhttp
的Request.Builder
,再通过Request.Builder#build
得到Request
实例,
RequestFactory#create -> RequestBuilder#get -> Request.Builder#build
接下来一个个详细解析。
2.5.2.1.3 RequestBuilder
在之前讲ParameterHandler
的时候,就提到过RequestBuilder
,所有的ParameterHandler#apply
方法,都是将对应参数以其能转换的方式add到RequestBuilder
当中。
而RequestBuilder
的作用,是构造出一个okhttp
的Request.Builder
,为build Request
做准备。先来看看RequestBuilder
的UML图:
从RequestBuilder
方法的定义看到了那些熟悉的方法,addHeader
、addPart
等等。
由于对应的方法都在ParameterHandler
提到过,所以就不再赘述了,直接看最核心的get
方法:
Request.Builder get() {
HttpUrl url;
// 如果不为空,this.urlBuilder是在第一次调用addQueryParam方法的时候构建的
HttpUrl.Builder urlBuilder = this.urlBuilder;
if (urlBuilder != null) {
url = urlBuilder.build();
} else {
url = baseUrl.resolve(relativeUrl);
if (url == null) {
// 解析relativeUrl失败
throw new IllegalArgumentException( "Malformed URL. Base: " + baseUrl + ", Relative: " + relativeUrl);
}
}
RequestBody body = this.body;
if (body == null) {
// Try to pull from one of the builders.
if (formBuilder != null) {
// 表单body
body = formBuilder.build();
} else if (multipartBuilder != null) {
// multipart body
body = multipartBuilder.build();
} else if (hasBody) {
// 如果http方法的定义是有body的,但是没穿这个参数,就构建一个空的body
body = RequestBody.create(null, new byte[0]);
}
}
MediaType contentType = this.contentType;
if (contentType != null) {
if (body != null) {
// 使用设置的contentType 覆盖掉RequestBody的Content-Type返回值 ContentTypeOverridingRequestBody其实就是一个代理类
body = new ContentTypeOverridingRequestBody(body, contentType);
} else {
// body为空的话 就只添加hander了
headersBuilder.add("Content-Type", contentType.toString());
}
}
// 继续添加url header method body 然后返回RequestBuilder实例
return requestBuilder.url(url).headers(headersBuilder.build()).method(method, body);
}
get
方法,整体看下来基本分为校验和通过将当前builder
的参数构建出RequestBuilde
r。在执行到这一步时,Service方法对应的参数都已经被转换成离构建最终的Request
之前一步的中间态了。
所以接下来,就是使用中间态的数据,真正构建Request
,也就是okhttp3.Request.Builder#build
。不过这里已经到okhttp的范畴了,等以后写okhttp的源码解析时,可以再聊聊。
至此,调用okhttp的最重要的Request
已经构建成功。回到retrofit.Call#execute
,接下来的步骤就是调用okhttp3.Call#execute
,然后来到最后一个关键组件:ResponseConverter
2.5.2.1.4 Retrofit.Call#parseResponse
直接看代码:
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
// 构建一个新的Response 因为上面已经拿着原始的body了 这么做可以只关注状态码等等信息
rawResponse =
rawResponse
.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
int code = rawResponse.code();
if (code < 200 || code >= 300) {
try {
// Buffer the entire body to avoid future I/O.
// 缓冲body数据 避免未来的IO
ResponseBody bufferedBody = Utils.buffer(rawBody);
// 因为状态码不是正常的状态码 所以这里返回一个错误的Response
return Response.error(bufferedBody, rawResponse);
} finally {
rawBody.close();
}
}
if (code == 204 || code == 205) {
// 204和205状态是没有body数据的
rawBody.close();
return Response.success(null, rawResponse);
}
// 构建一个包装异常的ResponseBody,将读取底层数据流时出现的异常进行捕获 并在下面抛出
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try {
// 因为在这一步, 可能会出现responseConverter将异常捕获并不处理
// 调用Convert组件进行转换
T body = responseConverter.convert(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
// 如果底层源抛出异常,则传播该异常,而不是指示它是运行时异常。
catchingBody.throwIfCaught();
throw e;
}
}
首先第一步,就将原始的Response
分为body
和其他响应结果进行了分割,避免错误的使用导致body
被重复读取。
随后在判断http code
非200多的情况下,将原始body
读取到缓存之后,构建了一个表示请求错误的Response
返回。
否则,在正常的非204
205
的情况下,就是使用convert
将body
数据读取转换成指定的对象了。在这一步,将原始的body
进行包装,将读取流的所产生的异常给捕获了,避免Convert
内部捕获但不抛出。
随后来到Convert
,这里用一个简单的ToStringConverter
来展示其核心概念
public static class ToStringConverterFactory extends Converter.Factory {
static final MediaType MEDIA_TYPE = MediaType.get("text/plain");
@Override
public Converter<ResponseBody, String> responseBodyConverter(
Type type, Annotation[] annotations, Retrofit retrofit) {
if (String.class.equals(type)) {
return ResponseBody::string;
}
return null;
}
@Override
public Converter<String, RequestBody> requestBodyConverter(
Type type,
Annotation[] parameterAnnotations,
Annotation[] methodAnnotations,
Retrofit retrofit) {
if (String.class.equals(type)) {
return value -> RequestBody.create(MEDIA_TYPE, value);
}
return null;
}
}
可以看到在调用完Convert
之后,整个请求就真正结束了。
关于OkhttpCall
的其他方法,都不是很难,同学们可以自行查看对应的源码。
2.5.2.2 ExecutorCallbackCall
Call
的另外一个实现,通过类的名字定义可以大概得知,这是为了支持异步调用所实现的Call
。实际上也确实如此,还记得最早的时候,在Platform
那一章节,讲到过如果是Android平台的话,会默认添加一个MainThreadExecutor
。而ExecutorCallbackCall
就是为了适配MainThreadExecutor
,达到Android平台下的回调效果(或者自定义Executor都行,在build Retrofit时可配置)
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@Override
public void enqueue(final Callback<T> callback) {
// 调用代理对象的enqueue方法
delegate.enqueue(
// 生成一个Callback
new Callback<T>() {
@Override
public void onResponse(Call<T> call, final Response<T> response) {
// 内部调用executor的execute方法,异步执行
callbackExecutor.execute(
() -> {
if (delegate.isCanceled()) {
// 取消
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
// 正常
callback.onResponse(ExecutorCallbackCall.this, response);
}
});
}
@Override
public void onFailure(Call<T> call, final Throwable t) {
// 失败 则使用executor的execute方法,将失败结果异步化
callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
}
});
}