Retrofit 源码剖析-深入
Posted wzgiceman
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Retrofit 源码剖析-深入相关的知识,希望对你有一定的参考价值。
背景
前一章节,先系统的讲解了关于Retrofit
实现当中的主要技术动态代理,本篇详细结合动态代理在Retrofit
中的应用,扩展到结合RxJava
来使用
思路
要深入研究一款开源项目最好的入口就是它所暴露出来的外部使用接口,按照这个思路,所以需要大体先了解Retrofit
的基本使用,这里就不阐述这些基础的知识,可以查看以前的博客
项目分析
想要弄清楚 Retrofit 的细节,先来看一下 Retrofit 源码的组成:
一个 retrofit2.http 包,里面全部是定义 HTTP 请求的注解,比如 GET、POST、PUT、DELETE、Headers、Path、Query 等等
余下的 retrofit 2.0 包中十几个类和接口就是全部 retrofit 的代码了,代码真的很少,很简单,因为retrofit把网络请求这部分功能全部交给了 okHttp 了
初始对象
先上一段使用Retrofit开始前的初始代码
//手动创建一个OkHttpClient并设置超时时间缓存等设置
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(basePar.getConnectionTime(), TimeUnit.SECONDS);
/*创建retrofit对象*/
Retrofit retrofit = new Retrofit.Builder()
.client(builder.build())
.addConverterFactory(ScalarsConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl(basePar.getBaseUrl())
.build();
这里的入口Builder()
方法进入源码
public static final class Builder
private Platform platform;
private okhttp3.Call.Factory callFactory;
private HttpUrl baseUrl;
private List<Converter.Factory> converterFactories = new ArrayList<>();
private List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
private Executor callbackExecutor;
private boolean validateEagerly;
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());
xxxx
Builder类中主要是记录请求过程中的一些配置信息,比如基础url
,当然重要的是addConverterFactory
方法记录Converter
数据转换器;addCallAdapterFactory
方法记录CallAdapter-HTTP
请求返回数据的类型.
Converter
数据转换器
Converter
数据转换器默认存放在retrofit-converters
中
Converter
采用接口抽象的方式,灵活了转换器的种类,常用的如上图中的Gson
和String
,同样这里可以可以自由扩展,实现Converter.Factory
接口
CallAdapter
请求返回数据的类型
工程位置如图
这里同Converter
数据转换器思想一样同样是采用抽象接口的方式,继承CallAdapter.Factory
类实现扩展,正如上图中箭头指示的显示扩展的RxJava2
的扩展
信息的转换
在Builder
记录完数据后通过build()
方法,将收集的信息传递给最后的Retrofit
对象中,并且初始了okhttp3.Call.Factory
请求处理类,从中可以看出Retrofit2.0
底层的http
请求默认就是通过okhttp3
处理的。
/**
* 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.");
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);
动态代理
Retrofit
初始完成以后,需要调用create
方法传入一个java接口抽象类对象作为参数。其实这一步真是Retrofit
动态代理生成的地方
源码:
@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, 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 serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
);
使用代码:
HttpTestService httpService = retrofit.create(HttpTestService.class);
httpService.getAllVedioBy(isAll());
上面HttpTestService
对象其实是一个动态代理对象,并不是一个真正的 HttpTestService
接口的implements
对象,当 httpService
对象调用 getAllVedioBy
方法时,执行的是下面动态代理方法。
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
其中主要ServiceMethod
是主要的处理对象
ServiceMethod
信息类
当调用loadServiceMethod
方法,将抽象HttpTestService中通过注解定义的信息收集起来存放于ServiceMethod
中,其中主要包含了一下数据:
OkHttpClient:发送网络请求的工具
RequestFactory: 类似于 Volley 中的 Request,包含了HTTP请求的Url、Header信息,MediaType、Method以及RequestAction数组
CallAdapter:HTTP请求返回数据的类型
Converter:数据转换器
最后Map<Method, ServiceMethod> serviceMethodCache
保存全部的 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;
debug
可查看当前ServiceMethod
对象收集的信息
收集完信息以后执行了
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
这一步对okhttp熟悉的同学肯定知道了,就是通过okhttp请求数据,其中serviceMethod是请求的地址信息,args是当前接口需要的参数信息。
执行完http请求以后,执行了
serviceMethod.callAdapter.adapt(okHttpCall);
这一步是将okhttp获取到的数据传递给一开始Retrofit
通过builder
指定的RxJavaCallAdapterFactory
类,那它是如何一步步处理的呢?
其实在一开始的获取serviceMethod
方法loadServiceMethod(Method method)
中,已经将Retrofit
对象传递给了serviceMethod
对象
核心代码:
//这里的this即是`Retrofit`对象
result = new ServiceMethod.Builder(this, method).build();
通过.Builder(this, method).build()
方法将Retrofit
一开始的builder
信息全部传递给了现在的serviceMethod
对象,所以当执行
serviceMethod.callAdapter.adapt(okHttpCall);
serviceMethod.callAdapter
便制动转换成了RxJavaCallAdapterFactory
,调用CallAdapter
抽象接口adapt
进入到RxJavaCallAdapterFactory
类中
源码:
@Override public <R> Observable<Response<R>> adapt(Call<R> call)
Observable<Response<R>> observable = Observable.create(new CallOnSubscribe<>(call));
if (scheduler != null)
return observable.subscribeOn(scheduler);
return observable;
最后生成RxJava
的Observable
对象,后面通过得到的Observable
对象就是对数据的处理了。
到此基于Retrofit
结合RxJava
源码的解读就完成了,回头看整个过程其实还是很简单,作者条理清晰理解起来也很简单,一口气终于把Retrofit
大体撸了一遍。
总结
Retrofit
非常巧妙的用注解来描述一个 HTTP
请求,将一个 HTTP
请求抽象成一个 Java
接口,然后用了 Java
动态代理的方式,动态的将这个接口的注解“翻译”成一个 HTTP
请求,最后再执行这个 HTTP
请求
Retrofit
的功能非常多的依赖 Java
反射,代码中其实还有很多细节,比如异常的捕获、抛出和处理,大量的 Factory
设计模式。
Retrofit
中接口设计的恰到好处,在你创建 Retrofit
对象时,让你有更多更灵活的方式去处理你的需求,比如使用不同的 Converter
、使用不同的 CallAdapter
,这也就提供了你使用 RxJava
来调用 Retrofit
的可能。
专栏
源码
建议
以上是关于Retrofit 源码剖析-深入的主要内容,如果未能解决你的问题,请参考以下文章
Android开发:深入源码剖析图片加载过程,面试官再也不能为难我了!