前言
前一篇分析了 OkHttp 的源码和流程,这一篇依然从 Retrofit 的使用角度并结合源码来分析,当然 Retrofit 是基于 OkHttp 的,所以OkHttp源码-流程-拦截器分析还是有必要了解的,而且 Retrofit 中使用了很多的设计模式,需要提前预览。
- 在开始流程前需要先看一下整体的流程图以及设计模式,这里就用了之前的 Stay 的 Retrofit 源码流程图,虽然更新了很多版本,但主要部分还是没变化的,看完这图,结合代码,最后再看图,再自己看源码总结,会更好理解的。
流程及分析
1.定义一个请求接口,包含请求方法
interface Api {
@GET("users/{user}/repos")
fun listRepos(@Path("user") user:String):Call<List<Repo>>
}
2.使用 Retrofit 请求
val retrofit = Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
val api = retrofit.create(Api::class.java)
val call = api.listRepos("")
call.execute()
call.enqueue(object :retrofit2.Callback<List<Repo>> {
override fun onFailure(call: retrofit2.Call<List<Repo>>, t: Throwable) {}
override fun onResponse(call: retrofit2.Call<List<Repo>>, response: retrofit2.Response<List<Repo>>) {}
})
一、构建Retrofit实例
先来看看 Retrofit 中的成员变量
其中比较关键的converterFactories
callAdapterFactories
//解析接口注解后相关信息的存储
private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
//请求工厂、默认为OkHttpClient
final okhttp3.Call.Factory callFactory;
final HttpUrl baseUrl;
//数据转换器工厂的集合,例如Gson转换
final List<Converter.Factory> converterFactories;
//网络请求适配器的集合
final List<CallAdapter.Factory> callAdapterFactories;
//回调执行器,在Android平台上就是通过Handler切换线程
final @Nullable Executor callbackExecutor;
//用来判断是否立即对我们的请求方法进行解析
final boolean validateEagerly;
1.Builder()方法
Builder(Platform platform) {
this.platform = platform;
}
public Builder() {
this(Platform.get());
}
Platform.get()
获取当前平台,一般是 Android,当然也支持其他平台比如 Java8 等
class Platform {
private static final Platform PLATFORM = findPlatform();
//通过findPlatfrom()获取平台信息
static Platform get() {
return PLATFORM;
}
//比较SDK版本 不空就返回Android平台
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
return new Platform(true);
}
...
static final class Android extends Platform {
Android() {
super(Build.VERSION.SDK_INT >= 24);
}
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
//通过Handler切换到主线程
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
}
2.baseUrl() 将String类型的URL转换为请求用的URL
public Builder baseUrl(String baseUrl) {
Objects.requireNonNull(baseUrl, "baseUrl == null");
return baseUrl(HttpUrl.get(baseUrl));
}
public Builder baseUrl(HttpUrl baseUrl) {
Objects.requireNonNull(baseUrl, "baseUrl == null");
List<String> pathSegments = baseUrl.pathSegments();
if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
}
this.baseUrl = baseUrl;
return this;
}
3.addConverterFactory(GsonConverterFactory.create()) 添加转换器
//主要就是创建带Gson对象的转换工厂
GsonConverterFactory.create()
//将带有Gson的转换器工厂添加到集合中
public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(Objects.requireNonNull(factory, "factory == null"));
return this;
}
4.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
添加一个请求的适配器工厂最后添加到 Builde 中的变量中,通过设计模式,像现在支持 Kotlin 的协程,也只需要切换工厂即可
5.build() 完成创建Retrofit实例
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
//一般不设置的话 就是默认OkHttpClient
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
//这里其实就是MainThreadExecutor()
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
....
//创建了Retrfit 为前面的变量赋值
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
二、创建接口实例
val api = retrofit.create(Api::class.java)
这部分用了动态代理以及外观模式创建了接口实例,以下是源码
public <T> T create(final Class<T> service) {
//1.主要做了一些验证比如是否接口以及是否需要提前缓存ServiceMethod对象
validateServiceInterface(service);
//2.代理接口中的方法
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
@Override public @Nullable Object invoke(Object proxy, Method method,
@Nullable 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);
}
//3.关键方法
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
ServiceMethod<?> loadServiceMethod(Method method)
在这个方法中解析接口中的注解等信息以及信息的缓存
ServiceMethod<?> loadServiceMethod(Method method) {
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
//解析方法的注解、返回类型、参数的注解以及参数类型
result = ServiceMethod.parseAnnotations(this, method);
//将解析出的信息添加到ConcurrentHashMap中供之后用
serviceMethodCache.put(method, result);
}
}
return result;
}
abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
//解析接口中的方法
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
// ...中间做了些验证 省略了
//将接口方法的调用调整为HTTP请求
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
abstract @Nullable T invoke(Object[] args);
}
具体的解析 RequestFactory parseAnnotations(Retrofit retrofit, Method method)
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
//获取注解
this.methodAnnotations = method.getAnnotations();
//获取参数类型
this.parameterTypes = method.getGenericParameterTypes();
//获取注解内容
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
RequestFactory build() {
for (Annotation annotation : methodAnnotations) {
//循环解析注解
parseMethodAnnotation(annotation);
}
...
return new RequestFactory(this);
}
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations( Retrofit retrofit, Method method, RequestFactory requestFactory)
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
...
//1.从Retrofit.java中的callAdapterFactories集合中获取对应的请求适配器
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
...
//2.从Retrofit.java中的converterFactories集合中获取对应的数据转换器
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
//检查是否kotlin协程中挂起的函数
if (!isKotlinSuspendFunction) {
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
}
...
}
最终转接到 OkHttp 的 Call ,并且adapt
调用之前生成的CallAdapter
的adapt
// loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
@Override final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
例如:默认的CallAdapter的实现如下:
//通过ExecutorCallbackCall传入executor执行call,call来代理同步/异步请求方法,实际的请求让okhttp来做
//后面3.2中可见详细
@Override
public Call<Object> adapt(Call<Object> call) {
return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
}
再例如RxJava2CallAdapter
:
@Override public Object adapt(Call<R> call) {
Observable<Response<R>> responseObservable = isAsync
? new CallEnqueueObservable<>(call)
: new CallExecuteObservable<>(call);
Observable<?> observable;
...
//生成observable 以rxjava的方式管理线程
if (scheduler != null) {
observable = observable.subscribeOn(scheduler);
}
if (isFlowable) {
return observable.toFlowable(BackpressureStrategy.LATEST);
}
if (isSingle) {
return observable.singleOrError();
}
if (isMaybe) {
return observable.singleElement();
}
if (isCompletable) {
return observable.ignoreElements();
}
return RxJavaPlugins.onAssembly(observable);
}
三、同/异步请求数据
1.同步请求call.execute()
@Override public Response<T> execute() throws IOException {
okhttp3.Call call;
synchronized (this) {
...
call = rawCall;
if (call == null) {
try {
//1.这里创建了OkHttp的call
call = rawCall = createRawCall();
} catch (IOException | RuntimeException | Error e) {
throwIfFatal(e); // Do not assign a fatal error to creationFailure.
creationFailure = e;
throw e;
}
}
}
if (canceled) {
call.cancel();
}
//2.解析OkHttp请求回来的数据
return parseResponse(call.execute());
}
//callFactory就是OkHttpClient
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;
}
//将OkHttp请求回的Response做解析
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.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.
ResponseBody bufferedBody = Utils.buffer(rawBody);
return Response.error(bufferedBody, rawResponse);
} finally {
rawBody.close();
}
}
if (code == 204 || code == 205) {
rawBody.close();
return Response.success(null, rawResponse);
}
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try {
//通过之前的赋值的转换器 将数据转为具体类型
T body = responseConverter.convert(catchingBody);
//封装到Response中返回
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
catchingBody.throwIfCaught();
throw e;
}
}
2.异步请求call.enqueue(Callback callback)
@Override public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(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 {
//依旧是使用了OkHttp的Call
call = rawCall = createRawCall();
} catch (Throwable t) {
throwIfFatal(t);
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
//依旧是使用了OkHttp的同步请求
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) {
throwIfFatal(e);
callFailure(e);
return;
}
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
throwIfFatal(t);
t.printStackTrace(); // TODO this is not great
}
}
@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) {
throwIfFatal(t);
t.printStackTrace(); // TODO this is not great
}
}
});
}
看到这里基本上的整体流程也就差不多了 再结合开头的图会比较清晰一点。
总结
总的来说,Retrofit 通过接口方法加注解的方式表明一个请求,通过动态代理的方式获取到方法上的注解以及返回值参数等数据,(因为通过反射获取消耗较大,所以会有ServiceMethod缓存),接下来,将这些数据适配为okhttp的call,通过适配器模式适配多种线程切换方式,例如rxjava、Executer/handler或Java8,增加了灵活性并且易于扩展,最后通过okhttp请求到数据后再通过之前配置的convert解析数据返回。
最后
- 如果文中如果有什么纰漏欢迎讨论与指出。