Retrofit原理及调用流程分析

准备步骤

Retrofit源码下载地址:https://github.com/square/retrofit

Retrofit源码目录结构:

官网Demo Link -> http://square.github.io/retrofit/

下图是第一个Demo,我们取名为Demo_1

Demo_1 调用流程分析

1 . 创建 RestAdapter ->

一、新new 一个RestAdapter 中的静态类 Builder.

二、Call Builder 类中的setEndpoint(String) 函数为此Builder实例中的Endpoint属性赋值,Endpoint实际上是一个利用实体表示的key-value键值对,指向当前用户指定的url和name

三、setEndpoint(String) 完成后,返回此Builder实例,继续Call 其 build()函数返回一个RestAdapter 的实例,在build()函数中会调用Builder实例的私有函数ensureSaneDefaults()

此函数会为Builder实例中还未赋值的属性赋予默认值,其中会用到Platform抽象类,在此抽象类里,分别有它的几个实现类(Base、Android、AppEngine(继承自Base)),会在其中判断是否使用了okhttp 或者 appengine,如果有就会使用它们,没有就会使用其他的网络请求客户端。他们都使用了缓存线程池(CachedThreadPool),但是设置的线程优先级不一样,并且负责执行回调线程的线程池也不一样,Platform#Base是在子线程里执行,Platform::Andrdoid是在主线程里执行。下图是Platform::Andrdoid类中的defaultClient函数实现。

四、ensureSaneDefaults()函数完成以后,就会调用RestAdapter 的私有构造器返回一个RestAdapter 的实例,如下图。

2 . 使用 RestAdapter ->

函数是这样被使用的:

GitHubService service = restAdapter.create(GitHubService.class);

返回一个用户自定义的GitHubService 接口,里面有一个listRepos函数调用之后可以返回一个List<Repo>的实体集合。那么在restAdapter调用create的时候干了什么事呢?

下图是create函数的实现部分。

其中先对传入的Class 进行校验:Utils.validateServiceClass(service),必须是接口,并且不能是一个没有自己函数并继承自其他父接口的空接口。

校验完成后返回一个动态代理类,我们想要知道retrofit使用用户自定义的接口干了什么事,就需要查看new RestHandler(getMethodInfoCache(service)) 的具体实现。

RestHandler 继承自 InvocationHandler 实现它的 invoke 函数,当代理类的接口函数被调用时,会先调用代理类的invoke 函数,然后在invoke 函数里通过反射调用用户指定的接口函数(不清楚JAVA动态代理请看Link: http://bbs.csdn.net/topics/390346645

查看invoke 函数的具体实现之间,我们先分析分析getMethodInfoCache(service)函数。

下面是getMethodInfoCache函数的实现部分

全局常量serviceMethodInfoCache的类型是Map<Class<?>, Map<Method, RestMethodInfo>>

该函数使用了同步代码块 synchronized 以serviceMethodInfoCache为对象锁,防止其他线程在该函数执行的时候入侵,之后在serviceMethodInfoCache查询service是否在其中存在,如果不存在,就新new 一个LinkedHashMap<Method, RestMethodInfo>加入其中,RestMethodInfo是一个final 类型的class,下面是它的申明

RestMethodInfo类的注释来看,它和用户自定义的接口有密切的关系,也就是说,用户接口中定义的函数,由该类来解析说明和发出请求。

之后就将methodDetailsCache(LinkedHashMap<Method, RestMethodInfo>类型)传入到RestHandler类的构造方法当中,为其的同名属性完成赋值的同时返回该类的实例。接下来我们就开始分析RestHandler中的invoke 函数,这可以说是retrofit的精髓所在。

下面是invoke 函数的实现

上面三张图贴出了invoke函数完整的实现,下面来分析每一步的调用流程。

(一)判断call的method是不是属于当前代理Object申明的,如果是就返回方法调用后的结果而不继续向下执行。

(二)调用getMethodInfo函数

传入参数为调用RestHandler构造方法时传入的methodDetailsCache(LinkedHashMap<Method, RestMethodInfo>类型)和具体调用的method(Method类型),返回值是一个RestMethodInfo的实例。getMethodInfo函数主要作用是将用户调用的method解析为一个RestMethodInfo实例,然后再将method和该RestMethodInfo实例以key-value键值对的形式绑定,存放在methodDetailsCache中,然后再将该RestMethodInfo实例返回。(ps: RestMethodInfo中的对Mehod接口解析是很重要的,但是这里作者就一笔带过了,读者自己看看吧,就是JAVA反射那套东西,还是很简单的)

(三)调用并返回invokeRequest函数
这里拿到了将method解析后的methodInfo(RestMethodInfo类型),判断该调用函数用户是想让它同步执行还是异步执行(利用RestMethodInfo中的isSynchronous属性判断),同步执行则进入到if判断,调用并返回invokeRequest函数

第一个参数RequestInterceptor接口是一个请求拦截器,能在请求执行之前向请求添加一些额外的数据,在最开始分析RestAdapter 创建的时候分析到ensureSaneDefaults 函数,如果没有在创建RestAdapter的时候传入自己实现的RequestInterceptor,那么Retrofit会给一个默认的RequestInterceptor空实现,指向RequestInterceptor接口类中的NONE属性。

第二个参数是刚才Method解析后的RestMethodInfo,第三个参数是用户调用函数时传入的参数数组。
下面是invokeRequest函数的实现





methodInfo.init() 
这个函数调用之后会将当前用户调用的方法进行进一步的解析,比如对@POST @GET @HEAD...etc 这些annotation的解析,并且每个实例只解析一次。
RequestBuilder requestBuilder = new RequestBuilder(serverUrl, methodInfo, converter);
从字面字面意思看,这个类和请求有关。确实,这个类里包含了用户请求网络所包含的各种参数,比如Host地址,Http协议头...etc 反正就是组成一个http请求所必要的东西。
Request request = requestBuilder.build();
由requestBuilder调用build函数产生一个Request类,该类是一个常量实体类,包含了最少的请求Http时所需要的信息。之后是请求信息的日志打印,在接下来关键的地方来了。

start 表示请求开始的时间,elapsedTime 表示该次请求花费的时间,而中间那句则是进行真正的网络请求,clientProvider 表示你在前面创建RestAdapter 时调调用ensureSaneDefaults函数所初始化的网络请求客户端(可能是OkClient, AndroidApacheClient,UrlFetchClient或者UrlConnectionClient四个的其中之一)。执行完成后返回一个response 这是一个Response常量实体类,和前面提到的Request常量实体类对应(一个表示请求实体,一个表示相应实体),里面存放着该次请求返回的Http协议头,状态码,body...etc , 关于执行的部分,这里就不多讲了,大家可以自己去查看三个请求客户端拿到Request之后是怎样执行请求的。
在请求之前还有一个profiler,大家应该注意到了,刚才我忽略了这个并没有讲它,现在可以告诉大家它的作用了。这里用到了AOP(面向切面)设计模式,如果用户设置了profiler的话,在请求的前后分别会调用profiler的beforeCall和afterCall函数,以通知用户请求的完成情况(在afterCall函数中传递了响应结果)。
之后的代码就是对response 的一个处理了,如果响应结果不在200到300之间,Retrofit会抛出一个自定义的异常进行进一步的处理,如果在200到300之间则会对response的请求数据做进一步的处理,比如demo_1中GitHubService 接口 --> listRepos函数返回一个List<Repo>的实体集合,那么在这里,将会走下面那段流程

利用converter(Converter接口类型,但实际上是GsonConverter,对Gson的一个封装) 将数据解析为用户想要返回的那个类型(如果判断是同步的话,但其实),如上述例子所提到的List<Repo>的实体集合。

(四)最后的分析
如果判断用户不是希望同步执行,那么invokeRequest函数的执行将会在之后执行。首先,会判断你是否使用了RxJava (https://github.com/Netflix/RxJava), 如果使用了RxJava ,则组建一个RxSupport(对RxJava 中类的简单封装),使用它的createRequestObservable函数对invokeRequest函数进行异步调用并返回一个ResponseWrapper。否则使用httpExecutor(前面初始化的时候被设置为CachedThreadPool(缓存线程池))对invokeRequest函数进行异步调用并返回一个ResponseWrapper。

总结

Retrofit使用的最核心的两个技术:动态代理和反射。

其实Retrofit无非就是让用户创建接口,使用自己指定的规则进行网络访问,把接口传入Retrofit,接口上附着的规则由Retrofit进行层层解析后,再进行实际的网络调用。Retrofit所做的事情就是帮助用户简化了大量的网络访问代码,用户只需写少量代码就能得到想要的结果。如果你懂OO设计,了解一定的设计模式且熟悉JAVA的API,那么你完全可以自己写一个类似Retrofit一样的网络框架!

这里是Freestyletime@foxmail.com,欢迎交流。

本人原创作品,转载请标明出处。

 

转载于:https://my.oschina.net/freestyletime/blog/296371

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值