Retrofit原理探究[源码解析]
本文分析基于retrofit:2.3.0
1、概述
Retrofit对于Android开发人员是一个较熟悉的网络请求框架,其简洁的使用方式,一度备受开发者的喜爱。我在去年年尾的时候的时候,也将Retrofit应用到新项目的开发,以取代原有的网络请求框架,不得不说Retrofit使用起来太方便了,短短的几行代码就可以搞定繁琐的网络请求。
在刚开始使用Retrofit的时候,我一度很好奇Retrofit是怎么做到如此的简洁的,如何将我们定义的接口转换为一个实际的网络请求的呢?
public interface ApiService {
@GET("json_it")
Call<String> test();
}
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(ScalarsConverterFactory.create())
.baseUrl("http://blog.csdn.net/")
.build();
Call<String> call = retrofit.create(ApiService.class).test();
call.enqueue(new Callback<String>() {
@Override
public void onResponse(Call<String> call, Response<String> response) {
}
@Override
public void onFailure(Call<String> call, Throwable t) {
}
});
Retrofit的显著优点如下:
1、可以配置不同HTTP client来实现网络请求,如okhttp、httpclient等;
2、支持同步、异步和RxJava
3、超级解耦等
本篇博文目标:结合源码,探究Retrofit如何将我们定义的接口转换为一个实际的网络请求的并拿到响应结果的。
预备知识:JDK动态代理、注解相关、OkHttp原理探究、Okio原理探究
如果你对以上预备知识都比较熟悉,那么你直接阅读源码将会比较轻松。
2、Retrofit整体执行流程
注意:上图只是简单的表述了Retrofit的整体流程思路,其具体的流程要比上图复杂的多。
a、JDK动态代理:
与静态代理相比较,动态代理的显著优点就是可以减少开发者自定义的Java文件的数量,因为动态代理为我们生成了所需的Java字节码文件【注意:动态代理是在运行时为我们生成Java字节码文件的,非编译时】。
JDK动态代理支持接口或类[必须实现某接口] ---- 生成的代理类是Proxy子类,同时会实现我们的接口中的所有方法,关键是我们实现的InvocationHandler,因为我们通过接口[开发者自定义的接口]调用动态代理生成的类中的方法都会被转发给InvocationHandler。这也是为什么我们仅仅定义一个接口文件就可以通过Retrofit去调用接口的原因,Retrofit的核心代码就是其实现的InvocationHandler。
Retrofit实现了自己的InvocationHandler,并在invoke方法中实现了主要的逻辑,接口方法的主要信息[注解信息、参数信息、方法名等]都包含在了Method参数中。
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
......}
因此,我们可以通过反射拿到构建一个OkHttp请求所需的全部信息。
b、ServiceMethod
主要有两个方法:toRequest和toResponse。
toRequest:根据上一步得到的信息构建一个OkHttp请求;
toResponse:根据我们设置的Converter【比如scalars】返回响应信息。
c、OkHttpCall
该类是Retrofit封装的OkHttp请求类,其主要作用是根据ServiceMethod的toRequest方法生成的OkHttp Request来生成OkHttp的RealCall。同时,利用ServiceMethod的toResponse方法返回我们需要的响应信息,比如接口返回的JOSN串。很显然ServiceMethod类是OkHttpCall的工具辅助类。
d、CallAdapter
看到Call肯定就知道是和请求相关
e、Converter
将响应解析成我们需要的形式,比如如果我们使用了Scalars,则会返回给我们JSON String串.
2.1、源码解析
//------------------------------第一部分--------------------------------------
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(ScalarsConverterFactory.create())
.baseUrl("http://blog.csdn.net/")
.build();
//------------------------------第二部分(主要)------------------------------
Call<String> call = retrofit.create(ApiService.class).test();
//------------------------------第三部分--------------------------------------
call.enqueue(new Callback<String>() {
@Override
public void onResponse(Call<String> call, Response<String> response) {
}
@Override
public void onFailure(Call<String> call, Throwable t) {
}
});
2.1.1、第一部分(创建Retrofit)
Builder(Platform platform) {
this.platform = platform;
// Add the built-in converter factory first. This prevents overriding its behavior but also
// ensures correct behavior when using converters that consume all types.
converterFactories.add(new BuiltInConverters());
}
public Builder() {
this(Platform.get());
}
可以看到,默认为我们添加了内置的Converter,当然通常情况下我们还会自己在加一些满足我们自己需求的Converter,比如Scalars。我们注意到这里有个Platform:.addConverterFactory(ScalarsConverterFactory.create())
.baseUrl("http://blog.csdn.net/")
.build();
addConverterFactory,baseUrl都很简单,就是设置Converter和请求的BaseUrl的,主要看下build()方法:public Retrofit build() {
if (baseUrl == null) {//必须设置baseUrl,否则抛出异常
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {//默认支持OkHttp
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();//Executor子类,稍后会看一下它的源码
}
// 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);
}
可以看到,build方法主要完成了基础设施的构建 ---- 网络请求(OkHttp相关)、辅助类构建(CallAdapter、Converter、Executor)。单独看下callbackExecutor,为什么要单独看呢?因为该类在后面会用于线程切换呦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);
}
}
}
Android是Platform的内部类,其内部又包含了MainThreadExecutor内部类,MainThreadExecutor就是我们在前面Retrofit的build方法中设置的callBackExecutor。由于handler在构造函数中传入了MainLooper,因此该Executor实现了切换到UI线程。2.1.2、第二部分(主要工作部分)
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.newInstance,很确定Retrofit使用了JDK的动态代理技术。而create方法返回值就是动态代理为我们生成的Java类,该类是Proxy的子类,同时实现了service中的所有方法。ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
Retrofit的执行全靠这几句代码了。首先通过ServiceMethod构造请求,然后将方法参数和ServiceMethod传递给OkHttpCall,因为OkHttpCall会使用ServiceMethod的toRequest和toResponse方法来构造Request和解析Response响应。 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的构造过程:Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
public ServiceMethod build() {
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
......
responseConverter = createResponseConverter();
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
......
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
......
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
......
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
......
return new ServiceMethod<>(this);
}
可以看到ServiceMethod为OkHttp发起网络请求进行了前期的准备工作,包括获取Method上的注解信息、参数的注解信息、创建或获取CallAdapter及Converter[这些CallAdapter、Converter既包括默认创建的,也包括我们在创建Retrofit的时候自己添加的,比如RxJavaCallAdapterFactory/ScalarsConverterFactory]。new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call<Object> adapt(Call<Object> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
Converter也是通过Retrofit的工厂类,最终在本例使用的是ScalarsConverterFactory。至于Retrofit是如何查找这些CallAdapter、Converter的,感兴趣的可以去看下源码。b、OkHttpCall
OkHttpCall是具体OkHttp最近的一层,因为Retrofit是通过OkHttpCall来向OkHttp发起真正的请求。该类的构造很简单:
OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {
this.serviceMethod = serviceMethod;
this.args = args;
}
private okhttp3.Call createRawCall() throws IOException {
Request request = serviceMethod.toRequest(args);
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
看到木有,OkHttpCall就是用ServiceMethod的toRequest来构造Request的,最终调用okhttp3.Call.Factory的newCall方法生成最终的RealCall。继续看OkHttpCall之enqueue,该方法在后面会用到,此处贴出来,方便后面查看,不想看的可以略过:
@Override public void enqueue(final Callback<T> callback) {
......
okhttp3.Call call;//真正的OkHttp3.Call终于出现了
Throwable failure;
synchronized (this) {
......
call = rawCall;
failure = creationFailure;
if (call == null && failure == null) {
try {
call = rawCall = createRawCall();//关键代码
} catch (Throwable 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)
throws IOException {
Response<T> response;
try {
response = parseResponse(rawResponse);//解析响应
} catch (Throwable e) {
callFailure(e);
return;
}
callSuccess(response);
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
private void callSuccess(Response<T> response) {
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
}
return serviceMethod.callAdapter.adapt(okHttpCall);
serviceMethod.callAdapter我们前面已经知道是啥了,如下:new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call<Object> adapt(Call<Object> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
adapt方法为我们返回了一个ExecutorCallBackCall对象,也就是invoke方法为我们返回了终极Call对象,也就是我们在此处的返回值Call: Call<String> call = retrofit.create(ApiService.class).test();
2.1.3、第三部分(发送请求)
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
delegate.enqueue(new Callback<T>() {//这里的delegate就是okHttpCall
@Override public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(new Runnable() {//切回UI线程
@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);
}
});
}
});
}
delegate.enqueue即调用了OkHttpCall的enqueue方法,其源码在b部分最后。完事!
上一篇: 网站SEO是否能够获取想要的流量?
下一篇: Project Euler 6-10题
推荐阅读
-
Laravel框架源码解析之模型Model原理与用法解析
-
spring5 源码深度解析----- 被面试官给虐懵了,竟然是因为我不懂@Configuration配置类及@Bean的原理
-
Spring MVC源码(三) ----- @RequestBody和@ResponseBody原理解析
-
Mybaits 源码解析 (五)----- 面试源码系列:Mapper接口底层原理(为什么Mapper不用写实现类就能访问到数据库?)
-
Mybaits 源码解析 (三)----- Mapper接口底层原理(为什么Mapper不用写实现类就能访问到数据库?)
-
持久层Mybatis3底层源码分析,原理解析
-
荐 【dubbo源码解析】--- dubbo的服务暴露+服务消费(RPC调用)底层原理深入探析
-
Andorid jar库源码Bolts原理解析
-
Laravel框架源码解析之入口文件原理分析
-
vue源码nextTick使用及原理解析