前言
上一篇文章中讲解了Retrofit的基本使用,分为如下几个步骤:
- Step1 定义接口层
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
- Step2 通过Retrofit创建接口层的一个代理对象
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
GitHubService service = retrofit.create(GitHubService.class);
- Step3 从代理对象中生成一个Call
Call<List<Repo>> repos = service.listRepos("octocat");
- Step4 通过Call来执行同步/异步请求
// 同步请求
repos.execute()
// 异步请求
repos.enqueue(new Callback(){...})
源码分析
下面就从这几个步骤切入,分析Retrofit内部的执行流程(笔者分析的版本是2.4.0),分析流程之前,我们先上结论,Retrofit的请求流程:
- Retrofit通过解析接口层定义的请求方法上的注解、参数信息来构造出Request请求对象
- 创建接口层的代理对象,来统一控制每个接口的访问,进而使每个接口访问最终走到了InvocationHandler#invoke方法中
- 通过网络请求适配器CallAdapter将网络请求对象进行平台适配(Android/Java8/Rxjava/Guava),来生成网络请求执行器
- 通过网络请求执行器来发送网络请求
- 通过数据转换器ConvertAdapter解析服务器返回的数据
- 通过对应平台的回调执行器CallbackExecutor将结果进行线程的调度(Android平台切换到主线程中)
- 客户端在对应线程中处理响应结果(Android平台在主线程中处理结果)
接口层定义我们的api接口,这个不用说了,根据Retrofit提供的相关注解来配置Server端的请求接口即可。
创建接口层的代理对象Retrofit#create(ApiService.class)
,我们先看下Retrofit对象的构建,内部是通过构建者模式构建Retrofit对象
public Builder() {
this(Platform.get());
}
public Retrofit build() {
// 必须指定baseUrl
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
// 如果没指定callFactory,则默认创建OkHttpClient
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
// 回调执行器,将回调切换到主线程,本质就是利用了handler
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// CallAdapter,请求执行器(发送网络请求)
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// ConvertAdapter,数据转换器(请求体的转换、响应体的转换)
List<Converter.Factory> converterFactories =
new ArrayList<>(1 + this.converterFactories.size());
// 系统内置的放在第一个位置
converterFactories.add(new BuiltInConverters());
// 添加我们定义的converterFactory
converterFactories.addAll(this.converterFactories);
// 构建Retrofit对象
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
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() {
private final Platform platform = Platform.get();
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// ...省略部分代码
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);
}
});
}
动态代理模式,这就就不再讲述了,这里通过动态代理,控制了所有接口方法的调用,就是说,每个接口方法调用都会走到这个invoke方法中,在这里我们可以实现统一控制,这种思路其实也可以想到,因为我们OkHttp发送网络请求可以抽象为以下几步:
- 构建Request
- 构建Call
- 执行Call
每个接口都是这种调用。那么我们就可以封装一个公共请求,对于不同的接口只是第一步构建Request不同,其它两步都是一样的。这里Retrofit其实也是这种思想。我们来具体分析:可以看到invoke方法中主要做了三件事:
- 将我们的请求方法包装成ServiceMethod
- 通过ServiceMethod和方法参数构建OkHttpCall
- 通过ServiceMethod将OkHttpCall进行代理包装
- 分析ServiceMethod构建
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;
}
这里将ServiceMethod进行缓存
public ServiceMethod build() {
// 拿到我们构建Retrofit时创建的CallAdapter,就是ExecutorCallbackCall它唯一做的事就是将原本Call的回调转发至主线程
callAdapter = createCallAdapter();
// 拿到我们方法的实际返回类型,比如Call<User>
responseType = callAdapter.responseType();
// 对该类型进行判断
if (responseType == Response.class || responseType == okhttp3.Response.class) {
throw methodError("'"
+ Utils.getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
// 拿到响应体转换器,也是根据我们创建Retrofit时添加的ConverterFactory获取
// 寻找的依据主要看该Converter能否处理你编写方法的返回值类型,默认实现为BuiltInConverters,仅仅支持返回值的实际类型为ResponseBody和Void,也就说明了默认情况下,是不支持Call<User>这类类型的。
responseConverter = createResponseConverter();
// 接下来就是对注解进行解析了,主要是对方法上的注解进行解析,那么可以拿到httpMethod以及初步的url(包含占位符)。
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
if (httpMethod == null) {
throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
if (!hasBody) {
if (isMultipart) {
throw methodError(
"Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
}
if (isFormEncoded) {
throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
+ "request body (e.g., @POST).");
}
}
// 这里是对方法中参数中的注解进行解析,这一步会拿到很多的ParameterHandler对象
// 该对象在toRequest()构造Request的时候调用其apply方法。
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
if (Utils.hasUnresolvableType(parameterType)) {
throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
parameterType);
}
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
if (parameterAnnotations == null) {
throw parameterError(p, "No Retrofit annotation found.");
}
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
if (relativeUrl == null && !gotUrl) {
throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
}
if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
throw methodError("Non-body HTTP method cannot contain @Body.");
}
if (isFormEncoded && !gotField) {
throw methodError("Form-encoded method must contain at least one @Field.");
}
if (isMultipart && !gotPart) {
throw methodError("Multipart method must contain at least one @Part.");
}
return new ServiceMethod<>(this);
}
这里ServiceMethod主要用于将我们接口中的方法转化为一个Request对象,于是根据我们的接口返回值确定了responseConverter,解析我们方法上的注解拿到初步的url,解析我们参数上的注解拿到构建RequestBody所需的各种信息,最终调用toRequest的方法完成Request的构建。
- 分析OkHttpCall的构建
OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {
this.serviceMethod = serviceMethod;
this.args = args;
}
仅仅通过构造函数进行简单的赋值
- 分析ServiceMethod#adapt(okHttpCall);
T adapt(Call<R> call) {
return callAdapter.adapt(call);
}
这里是直接调用CallAdapter的adapt()方法,这个CallAdapter之前构建Retrofit的时候已经创建了,就是ExecutorCallAdapterFactory.get()返回值
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call<Object> adapt(Call<Object> call) {
// 返回值是ExecutorCallbackCall
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
可以看到adapt返回的是ExecutorCallbackCall对象,下面分析ExecutorCallbackCall
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) {
checkNotNull(callback, "callback == null");
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}
@Override public void onFailure(Call<T> call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
可以看出ExecutorCallbackCall仅仅是对Call对象进行封装,类似装饰者模式,只不过将其执行时的回调通过callbackExecutor进行回调到主线程中去了。
- 分析Call的执行
在上面的分析中,我们已经拿到了ExecutorCallbackCall类型的Call对象,通过这个Call对象我们就可以直接调用enqueue进行异步请求了,看下源码的实现
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}
@Override public void onFailure(Call<T> call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
可以看到通过callbackExecutor将回调切换到了主线程执行,但是实际的请求还是通过delegate完成的,这个delegate就是OkHttpCall对象。看下它的enqueue方法
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
okhttp3.Call call;
Throwable failure;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
call = rawCall;
failure = creationFailure;
if (call == null && failure == null) {
try {
call = rawCall = createRawCall();
} catch (Throwable t) {
throwIfFatal(t);
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
}
可以看到,它内部又是调用了okhttp3.Call的enqueue,相当于又封装了一层,接下来看下okhttp3.Call的创建
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = serviceMethod.toCall(args);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
/** Builds an HTTP request from method arguments. */
okhttp3.Call toCall(@Nullable Object... args) throws IOException {
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
contentType, hasBody, isFormEncoded, isMultipart);
@SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
int argumentCount = args != null ? args.length : 0;
if (argumentCount != handlers.length) {
throw new IllegalArgumentException("Argument count (" + argumentCount
+ ") doesn't match expected count (" + handlers.length + ")");
}
for (int p = 0; p < argumentCount; p++) {
handlers[p].apply(requestBuilder, args[p]);
}
return callFactory.newCall(requestBuilder.build());
}
可以看到这里通过serviceMethod.toCall(args)先构造了Request对象,然后构造了Call对象,okhttp3.Call的enqueue方法中还涉及了一个parseResponse方法
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
// 解析响应
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
分析下parseResponse方法
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
// ...省略部分代码
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
T body = serviceMethod.toResponse(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
// If the underlying source threw an exception, propagate that rather than indicating it was
// a runtime exception.
catchingBody.throwIfCaught();
throw e;
}
}
可以看到这里通过serviceMethod对ResponseBody进行转化,然后返回,转化实际上就是通过responseConverter的convert方法。
/** Builds a method return value from an HTTP response body. */
R toResponse(ResponseBody body) throws IOException {
// 通过转换器进行数据转换
return responseConverter.convert(body);
}
自定义Converter.Factory
源码中Converter.Factory定义如下:
abstract class Factory {
// 响应体的转换
public @Nullable Converter<ResponseBody, ?> responseBodyConverter(Type type,
Annotation[] annotations, Retrofit retrofit) {
// !!!这里根据type判断是否是自己能处理的类型,不能的话,一定要return null,交给后面的Converter.Factory
return null;
}
// 请求体的转换
public @Nullable Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
// 逻辑实现
return null;
}
...省略部分代码
}
主要是实现请求体的转换,和响应体的转换。
添加Converter.Factory的方法为addConverterFactory
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.example.com/")
//.addConverterFactory(GsonConverterFactory.create())
.build();
源码中已经定义了一个内置的转换器,BuiltInConverters,这里就不分析了,可以直接看下源码,我们看下拓展库GsonConverterFactory的实现
public final class GsonConverterFactory extends Converter.Factory {
public static GsonConverterFactory create() {
return create(new Gson());
}
public static GsonConverterFactory create(Gson gson) {
return new GsonConverterFactory(gson);
}
// 构建了一个Gson对象
private final Gson gson;
private GsonConverterFactory(Gson gson) {
if (gson == null) throw new NullPointerException("gson == null");
this.gson = gson;
}
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
// 构建Gson的响应转换器
return new GsonResponseBodyConverter<>(gson, adapter);
}
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
// 构建Gson的请求转换器
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonRequestBodyConverter<>(gson, adapter);
}
}
源码很简单,就是实现了对象->json字符串以及json字符串->对象的映射。
reqeustBodyConverter
主要是对应@Body
注解,完成对象到RequestBody
的转化,其实@Part
等注解也会需要responseBodyConverter
,只不过我们的参数类型都是RequestBody
,由默认的converter
处理了。
resposneBodyConverter
主要对应响应数据到返回类型的转换,这个类型对应Call<XXX>
里面的泛型XXX
,一定要注意,检查type
如果不是自己能处理的类型,记得return null
(因为可以添加多个,你不能处理return null
,还会去遍历后面的converter
)
思考与感悟
- Retrofit非常巧妙的利用注解来描述一个HTTP请求,它将一个HTTP请求抽象为一个接口方法,然后通过动态代理的方式将一个方法注解参数等信息
翻译
成一个具体的HTTP请求,最后执行这个请求 - Retrofit利用了大量的设计模式,如工厂、适配器、代理、外观、适配器等。
- Retrofit的可配置性非常强,比如开放了数据转换器接口、网络执行器接口,客户端可以根据需求自我实现
- Platform平台的设计,Retrofit内部根据类加载的思路确定当前的运行环境,从而配置不同的执行