Retrofit2源码分析
Retrofit是一个基于okhttp的网络请求工具,和google的volley相似,但是更加简洁,可以简洁到调用一个Java方法的方式去请求一个api.
一、如何使用?
通过一个登录接口来看下retrofit是如何使用的,首先配置app级别的gradle依赖,这里涉及json数据转换,所以需要添加适配:converter-gson
依赖如下:
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.3.0'
然后创建一个Api接口类
// Api.java
public interface Api {
@POST("login")
Call<ResponseBody> login(@Body LoginReq req);
}
// 初始化retrofit
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("http://10.5.16.237:8080/DemoApi/").build();
// 动态代理得到Api实例
Api api = retrofit.create(Api.class);
// 调用登录接口
api.login(new LoginReq("chengyuan", "12345")).enqueue(new retrofit2.Callback<ResponseBody>() {
@Override public void onResponse(retrofit2.Call<ResponseBody> call,
retrofit2.Response<ResponseBody> response) {
try {
System.out.println("retrofit->" + response.body().string());
} catch (Exception e) {
e.printStackTrace();
}
}
@Override public void onFailure(retrofit2.Call<ResponseBody> call, Throwable t) {
}
});
假设以上代码是通过点击登录按钮来调用的,运行一下:
05-25 11:10:33.676 8540-8540/com.okhttp.okhttp I/System.out: retrofit->"login success"
详细用法查看官网:http://square.github.io/retrofit/
当然,这不是重点,接下来我们看下retrofit是什么实现的?
二、源码分析
看源码之前,我们可以先问自己几个问题,带着问题看源码往往效率更高。
问题一:retrofit是对okhttp的封装,那retrofit是如何一步一步完成对okhttp接口调用的?
先看下retrofit对象是如何构建出来的?
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("http://10.4.33.125:8080/DemoApi/").build();
可以看到,构建retrofit传入了baseUrl,并且添加了一个GsonConverterFactory,然后执行build方法,接下来看下build做了哪些事情?
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
callFactory默认是一个OkHttpClient,okhttp的Call实例可以猜测是callFactory生成的。然后可以看到通过platform.defaultCallbackExecutor()生成一个callbackExecutor对象,跟踪platform后发现
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);
}
}
}
defaultCallbackExecutor实际上是new MainThreadExecutor(),把runnable发送到主线程消息队列执行,好处就是主线程可以直接访问view控件嘛,我们在使用retrofit的时候发现onResponse回调接口可以直接访问view,猜测和这个callbackExecutor有关。
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
这个coverterFactories存放的是GsonConverterFactory.create(),有了gson,我们可以很方便的把json转成实体类
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
adapterFactories和coverterFactories类似,不过即使我们在构建retrofit时没有指定,adapterFactories仍然会有个默认值,通过platform.defaultCallAdapterFactory(callbackExecutor)得到,跟踪代码
@Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
if (callbackExecutor == null) throw new AssertionError();
return new ExecutorCallAdapterFactory(callbackExecutor);
}
adapterFactories存放的是ExecutorCallAdapterFactory对象,继续查看ExecutorCallAdapterFactory实现
final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
final Executor callbackExecutor;
ExecutorCallAdapterFactory(Executor callbackExecutor) {
this.callbackExecutor = callbackExecutor;
}
@Override
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) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
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);
}
});
}
});
}
//省略非关键代码
}
ExecutorCallAdapterFactory继承了CallAdapter.Factory,通过重写get方法来得到CallAdapter实例,CallAdapter是一个接口类,通过adapt来构建Call对象来调用网络接口,这里不是直接调用,而是通过Call的代理类ExecutorCallbackCall来完成,详细查看ExecutorCallbackCall的enqueue接口可以发现,onResponse回调接口是由callbackExecutor发射runnable到主线程处理的,所以可以在onResponse处理view控件,这个也印证了之前的猜测,确实和callbackExecutor有关。
整理一下思路:ExecutorCallAdapterFactory是为了构建CallAdapter从而得到Call实例来调用网络接口;下面我们再找找CallAdapter的adapt什么时候被触发?
api = retrofit.create(Api.class);
我们看到retrofit调用了create方法,查看create实现,发现用到了动态代理,不清楚动态代理的,可以查看Design pattern–代理模式
@SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
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 {
// 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);
}
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
可以理解为动态生成了代理类$Proxy,我们调用的login接口会代理到InvocationHandler#invoke方法,可以看到invoke的method参数指向我们调用的login接口,重点来了
serviceMethod.callAdapter.adapt(okHttpCall);
我们刚才再想callAdapter的adapt原来是在这里触发的。查看serviceMethod的callAdapter,其实就是从adapterFactories取出来的,我们构建retrofit的时候有保存了一个默认值:platform.defaultCallAdapterFactory(callbackExecutor),serviceMethod.callAdapter指向的是正式ExecutorCallAdapterFactory通过get构建的callAdapter,然后调用adapt接口得到Call实例,Call实例被ExecutorCallbackCall代理。adapt的参数是OkHttpCall,那说明ExecutorCallbackCall代理了OkHttpCall的接口逻辑,最终由OkHttpCall调用okhttp3.Call.
看到这里我们基本上已经把整个调用逻辑分析了一遍,也完成了对问题一的回答。
问题二:为什么要在retrofit初始化的时候动态传入GsonConverterFactory呢?这么设计有什么好处?
看源码前我猜测是为了解耦,同时提高代码灵活性,做到插件式的即插即用吧。
我们还是分析下GsonConverterFactory在源码中是如何使用的?
gson的作用无非方便就是json和实体类之间格式转换,通常我们会在拿到接口返回数据的时候使用gson转成实体类,这里也一样,我们知道调用login接口最终还是通过OkHttpCall调用的okhttp3.Call.enqueue或者execute完成
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {
Response<T> response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
callSuccess(response);
}
// 省略非关键代码
}
继续跟踪parseResponse发现是通过T body = serviceMethod.toResponse(catchingBody);来转换数据格式的,查看具体实现
/** Builds a method return value from an HTTP response body. */
R toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
}
接着看代码
public ServiceMethod build() {
// 省略非关键代码
responseConverter = createResponseConverter();
...
}
查看完createResponseConverter代码发现,responseConverter是调用保存在converterFactories中的GsonConverterFactory的responseBodyConverter方法得到的。最终由GsonResponseBodyConverter的convert方法完成格式转换
final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, 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 IOException {
JsonReader jsonReader = gson.newJsonReader(value.charStream());
try {
return adapter.read(jsonReader);
} finally {
value.close();
}
}
}
到这里,分析完了GsonConverterFactory在retrofit源码中的使用情况,再看下为什么要这么设计?
好处就是可以根据项目情况灵活使用如下插件
retrofit的大部分逻辑都是在ServiceMethod中完成的,每一个接口只初始化一次,并且保存到serviceMethodCache缓存中
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;
}
接口初始化的工作包括解析接口参数、解析类似@POST @Body等注解和构建CallAdapter\ResponseConverter等操作,由于代码太多,不做进一步分析了
最后在上一张流程图
想要进一步了解retrofit是如何解耦的可以参考Retrofit分析-漂亮的解耦套路
以上!