Retrofit2源码分析
来源:互联网 发布:湘阴农村淘宝招聘信息 编辑:程序博客网 时间:2024/06/09 21:49
前言
很长一段时间没有写博客,主要原因是工作了感觉没什么时间了(其实是因为懒)。最近在项目中引用了 Retrofit+Rxjava 组合,感觉写的非常刺激。秉着不单单只停留在会用的层次上,还需要对源码进行分析的理念,决定是时候学(zhuang)习(bi)一波了。
此篇博客所需知识
- 对 适配器模式 有一定的了解。
- 会使用 Retrofit 以及 Rxjava
- 知道如何优雅的装逼,故意把一个简单的东西说的很复杂。
Retrofit 使用例子
Retrofit retrofit = new Retrofit.Builder() .addConverterFactory(GsonConverterFactory.create())// .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .baseUrl("http://gc.ditu.aliyun.com/") .build();MyService service = retrofit.create(MyService.class);Call<City> call = service.getCity("汕头市");call.enqueue(new Callback<City>() { @Override public void onResponse(Call<City> call, Response<City> response) { Log.e("cat", "response:" + response.body().toString()); } @Override public void onFailure(Call<City> call, Throwable t) { t.printStackTrace(); Log.e("cat", "fail:" + t.getMessage()); }});
上述代码就是我们使用 Retrofit 的典型代码,对 Retrofit 这个库还不熟悉的请先自行去学习这个库,这篇博客不讲使用,只讲源码,这篇博客不讲使用,只讲源码,这篇博客不讲使用,只讲源码。
源码分析
源码相关知识普及
在看其源码之前,首先有些东西得普及一下,以免跟踪源码的时候有些玩意不知道干什么用的。
首先,Retrofit 最开始会通过 Builder 模式 构造出一个 Retrofit 对象,大部分属性,一旦构造完,便不允许修改。当需要使用的时候,调用 Retrofit.create(Service.class) 初始化我们的业务对象。Retrofit.create() 方法内部使用的是动态代理模式,会拦截我们调用 Service 的每一个方法。为啥要拦截呢?主要是将 Service 接口 中的方法中的注解,封装成一个请求对象 OkHttpCall,并且使用适配器模式来对 OkHttpCall 进行适配,转换成我们需要的类型,例如 Observable。Retrofit 内部会保存有一个 Adapter 以及 Converter 的 list,封装请求对象的时候会遍历这两个集合,寻找适合这个请求的 Adapter 以及 Converter。
上述过程主要是请求的构建,同时 Retrofit 确实也不负责其他功能,其网络请求功能主要还是交给 OkHttp 去实现,依我看来,Retrofit 只是充当了一个粘合剂而已。
三个个重要的对象
1. CallAdapter: 主要是用来对 OkHttpCall 进行适配,常用的就是 RxJavaCallAdapterFactory,构造的时候不指定的话,默认实现是 ExecutorCallAdapterFactory 由工厂生成的。
2. Converter: 用来对后台返回的数据进行转换的转换器,一般后台会返回 json 数据,我们一般会使用 GsonConverterFactory 来进行转换。
3. ServiceMethod: 根据接口中的方法以及注解生成的对象,封装了对应方法的 converter 以及 adapter 等(注意,不同的方法可能有不同的 convertor 以及 adapter)。
4. OkHttpCall:这个东西我很难描述是什么东西,主要是用来执行请求的吧。用过 OkHttp 的应该知道。
构造 Retrofit
构造 Retrofit 采用的是 Builder 设计模式,我们直接点进去 build() 方法看看就好,因为中间的一系列链式调用无非就是一些赋值而已。
Retrofit.Builder.build()
/** * Create the {@link Retrofit} instance using the configured values. * <p> * Note: If neither {@link #client} nor {@link #callFactory} is called a default {@link * OkHttpClient} will be created and used. */ public Retrofit build() { if (baseUrl == null) { throw new IllegalStateException("Base URL required."); } // callFactory 是构造 Retrofit 时候调用 Buidler.callFactory() 进行赋值的,效果跟 Buidler.clien() 是相同的。 //如果在构造 Retrofit 时没有进行赋值,则默认采用的是 OkHttpClient okhttp3.Call.Factory callFactory = this.callFactory; if (callFactory == null) { callFactory = new OkHttpClient(); } // callbackExecutor 是构造 Retrofit 时候调用 Buidler.callbackExecutor() 进行赋值的。默认实现是将 Runnbale post 到主线程中执行。 Executor callbackExecutor = this.callbackExecutor; if (callbackExecutor == null) { callbackExecutor = platform.defaultCallbackExecutor(); } // 对 adapterFactories 以及 converterFactories 进行保护性复制,防止由于类的外部持有 adapter 或者 convertor 的 引用从而能能在构造 Retrofit 后仍能从外部对其进行改变。 // 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); }}
创建完 Retrofit 后就需要实例化我们的业务对象 Service 了,点进去 Retrofit.create() 方法中看下。
初始化业务对象
Retrofit.create()
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, 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); } //上面两个 if 可以省略。下面这几句主要是将方法封装成一个请求对象以及对 okHttpCall 进行适配。 // 根据接口方法中的注解等封装成一个 serviceMethod ServiceMethod serviceMethod = loadServiceMethod(method); // 封装成一个请求对象。 OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args); // 对 okHttpCall 进行适配,转换成我们需要的返回值类型。 return serviceMethod.callAdapter.adapt(okHttpCall); } });}
这段代码主要是生成我们的业务对象,这是根据我们定义的接口返回来的代理对象,以后我们每次调用业务方法都会被其进行拦截,被其封装成一个请求对象,同时转换成我们需要的类型,这里由于我们没有指定 Adapter,所以采用的是 Retrofit 默认的 ExecutorCallAdapterFactory。
Retrofit.loadServiceMethod
ServiceMethod loadServiceMethod(Method method) { ServiceMethod result; // 查看是否有缓存对应 method 的 serviceMethod,有则直接取出,没有就重新生成一个 serviceMethod,并 put 进缓存 map 里面。 synchronized (serviceMethodCache) { result = serviceMethodCache.get(method); if (result == null) { result = new ServiceMethod.Builder(this, method).build(); serviceMethodCache.put(method, result); } } return result;}
ServiceMethod 的构建 #ServiceMethod.Buidler.build()
public ServiceMethod build() { // 创建指定 method 的 adapter,内部实现是传入方法的返回值以及注解,遍历 Retrofit 中的 adapter list 进行匹配,通过工厂模式生成 adapter。 responseConverter 同理。 callAdapter = createCallAdapter(); responseType = callAdapter.responseType(); responseConverter = createResponseConverter(); //解析方法的注解,如 @Get @FormUrlEncode 这种注解,注意,不是参数的注解 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]; if (Utils.hasUnresolvableType(parameterType)) { throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s", parameterType); } Annotation[] parameterAnnotations = parameterAnnotationsArray[p]; parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations); } ... 省略了对字段校验的代码 return new ServiceMethod<>(this);}
上面代码就完成了一个 ServiceMethod 对象的创建,当调用 ServiceMethod.toRequest 方法的时候,就生成了一个请求对象 Request
对 okHttpCall 进行适配
再次回到 Retrofit.create 方法,有如下一段。
return serviceMethod.callAdapter.adapt(okHttpCall);
serviceMethod 我们知道了,callAdapter 是什么呢?如果你在构造 Retrofit 不指定的话,默认实现就是 通过 ExecutorCallAdapterFactory 工厂生产出来的,来看一下这个类先。
final class ExecutorCallAdapterFactory extends CallAdapter.Factory {final Executor callbackExecutor;ExecutorCallAdapterFactory(Executor callbackExecutor) { this.callbackExecutor = callbackExecutor;}// serviceMethod 生成 callAdapter 遍历 Retrofit 中的 adapter list 时会调用这个方法,这其实是个工厂方法,只不过这里只有一个实现,目测这破工厂也快倒闭了。RxJavaCallAdapterFactory 中有挺多实现的。@Overridepublic CallAdapter<Call<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) { if (getRawType(returnType) != Call.class) { return null; } //实际的返回类型,即 Call 或者 Observable 包装的类型。 final Type responseType = Utils.getCallResponseType(returnType); return new CallAdapter<Call<?>>() { @Override public Type responseType() { return responseType; } // 将 okHttpCall 进行包装,返回 Retrofit 的默认类型 ExecutorCallbackCall。这段其实就是 Retrofit 中的使用的适配器模式,将 Call 转换成我们想要的类型。 // 如果我们在构造 Retrofit 时指定了 CallAdapter 例如 Rxjava,则 adapt 会返回相应的类型。具体实现可以自行查看 RxJavaCallAdapterFactory @Override public <R> Call<R> adapt(Call<R> call) { return new ExecutorCallbackCall<>(callbackExecutor, call); } };}
上述方法就是系统默认的 ExecutorCallAdapterFactory,我们来看看其生成的 CallAdapter 是如何进行适配(adapt) 的。查看 adapt 方法返回的 ExecutorCallbackCall<>(callbackExecutor, call)
static final class ExecutorCallbackCall<T> implements Call<T> {final Executor callbackExecutor;final Call<T> delegate;//这里传入的 delegate 就是 okHttpCallExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) { this.callbackExecutor = callbackExecutor; this.delegate = delegate;}// 其实就是把 enqueue 方法代理给 okHttpCall@Override public void enqueue(final Callback<T> callback) { if (callback == null) throw new NullPointerException("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); } }); } });}
这段没什么好说的,当我们调用 Call.enqueue 的时候,实际上调用的是 okHttpCall 的 enqueue。
总结
最后,再梳理一下。
- 首先,使用建造者模式生成一个 Retrofit。
- 生成我们的业务对象,调用 Retrofit.create 方法,通过动态代理模式返回一个代理对象,以后调用业务对象的任意一个方法, 都会被拦截。将 Service 接口中的每一个方法以及方法中的注解封装成一个请求对象。
- 封装请求对象的具体逻辑是,根据方法的返回值以及注解,遍历 Retrofit 中的 adapter list 以及 convertor list,通过工厂方法返回合适的 adapter 或者 convertor。然后,对 方法的注解进行解析,最后将解析后的结果、adapter 以及 convertor 封装成一个 serviceMethod。
- serviceMethod 封装后,会初始化一个 OkHttpCall ,这个对象就是真正执行请求的对象。
- 最后,调用 serviceMethod 的 adapter 的 adpt 方法对 okHttpCall 进行适配,返回我们想要的类型。例如 Observable。
Retrofit 这个库是一个巧妙的运用了各种设计模式的经典库,有许多地方值得我们学习。虽然能大概看懂其实现,但是要学会其中的思想,仍然需要一定时间的沉淀。同时,这个库比较容易读懂,绝对是我们进阶中级 Android 开发的良品。
- Retrofit2.0源码分析
- Retrofit2源码分析
- Retrofit2 源码分析
- Retrofit2 源码分析
- Retrofit2.0源码分析
- Retrofit2 源码分析
- retrofit2源码分析
- Retrofit2源码分析
- retrofit2源码分析
- retrofit2.0源码分析
- Retrofit2实现源码分析
- Retrofit2源码分析
- Retrofit2 源码分析(清晰版)
- Retrofit2源码初探
- Retrofit2源码解读
- Retrofit2源码解析
- Retrofit2 源码解析
- Retrofit2.0源码解析
- Handler、Loop、MessageQueue的关系
- GlobalAlloc、GlobalLock和GlobalUnLock详解
- cocos2d-x 3.0 在C++中调用lua函数
- 阅读论文:Distributed GraphLab
- 错误代码:DNS_PROBE_FINISHED_NXDOMAIN 有部分网页打不开.
- Retrofit2源码分析
- 九、线性查找(BFPRT)
- Java 设计模式-组合模式
- window10 genymotion
- 关于Qt双缓冲
- 秒杀系统架构分析与实战
- [LeetCode]Repeated DNA Sequences
- python:if __name__ == '__main__': 的作用
- Linux内存管理之三 页的分配和释放