Retrofit2 源代码初步解读

前段时间把公司的网络库替换成Square的Retrofit2,大幅提高工作效率。工作之余,抽点时间,喝杯茶简单研读了下Retrofit2的源代码,堪称设计模式的典范。

本文从什么是Retrofit2、Retrofit2如何使用、Retrofit2内部原理3个步骤来解读Retrofit2。

什么是Retrofit2

Retrofit2 可以说是目前最流行的类型安全网络库,是Square公司的一个开源项目,通过注解来创建restful API接口。目前2.0版本已经稳定,下文如无特殊说明,均指2.0版本。

Retrofit2使用步骤

Retrofit2的使用很简单,主要分为以下几个步骤:

  1. 创建Interface接口,通过注解标识客户端与后台约定的API接口

public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}

  1. 创建Retrofit实例,生成Interface的实现类(动态代理实现对象)

Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com")
.build();
GitHubService service = retrofit.create(GitHubService.class);

  1. 调用上面创建的实现类中的API请求方法,取得Call对象

Call<List<Repo>> repos = service.listRepos("octocat");

  1. 根据调用场景异步或同步,执行call对象的同步或异步执行方法,异步方法需要传入Callback回调参数
  • 异步:call.enqueue(Callback callback)
  • 同步:call.execute()

Retrofit2内部原理

根据上面Retrofit2使用步骤,我们逐步来探究Retrofit内部的奥秘

  • 第一步没啥好说的,就是根据跟服务器的接口协议文档写注解接口。
  • 根据接口创建相关执行代理对象。从源代码可以看到此处使用了JAVA中的动态代理技术,类似于方法hook,调用接口中的任何方法都会事先调用proxy中的钩子方法。


    动态代理

    这里的钩子方法为

loadMethodHandler(method).invoke(args)

我们一步步跟下去,接着看loadMethodHandler方法

loadMethodHandler方法

loadMethodHandler方法就是根据method返回相应的methodHandler。MethodHandler顾名思义为方法处理器,method与MethodHandler一一对应的关系是采用map实现的。一个method对应一个MethodHandler,如果当前method对应handler不存在则会创建一个然后再put到map里面。
通过method获取对应的handler后,调用handler的invoke()方法。
handler的invoke方法

我们再往里面分析,可以看到invoke方法使用CallAdapter进行Call<R>的转换。Call转换工作是通过CallAdapter call适配器的adapt方法进行的。

  • CallAdapter是什么?顾名思义就是Call的适配器,作用就是创建/转换Call对象,把Call转换成预期的格式。CallAdatper创建是通过CallAdapter.factory工厂类进行的,本身只有一个转换方法adapt()。创建CallAdatper Factory需要实现Factory接口,接口只包含一个方法CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit); 通过传入的returnType参数来返回相应的CallAdapter。

interface Factory {
CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit);
}

DefaultCallAdapter为Retrofit2自带默认Call转换器,用来生成OKHTTP的call请求调用。
Retrofit内部维护着一个calladapterFactory列表。Retrofit会依次遍历adapterFactory list列表来查询并返回能够处理对应returntype的calladapter,如果一个都获取不到,则抛出illegalArgument异常。Retrofit内置2种callAdapter,都只能处理返回类型为Call的调用。两者唯一区别是Call的回调是否通过指定的Executor执行。

  • 异步/同步发起请求。请求最终生成的还是okhttp raw call,然后再分别进行异步/同步调用。okhttp raw call的生成是通过RequestFactory来完成的。
RequestFactory生成Request方法
  • 返回请求的解析。服务器返回的数据格式一般为JSON/XML,采用相应的解析器ResponseConverter转换成Class对象。ResonseConverter实现Converter接口,Converter接口只有一个T convert(F value)方法和Factory工厂内部类。用户自定义Converter需实现Converter接口。Retrofit内部维护着一个ResonseConvert列表,代表retrofit解析结果的能力。Retrofit解析的时候依次从列表中取出converter尝试做转换,转换成功则返回转换Class对象,如果转换失败,继续选取列表中下一个Converter直到最后失败抛出IllegalArgumentException(Could not locate ResponseBody converter for **)异常。
系统处理Response解析,查找匹配converter方法

总结

Retrofit源代码初步解读就到此结束,在分析的过程中深刻感觉顶尖高手写的代码是多么的巧妙,需向大牛们多多学习。
Retrofit2库主要涉及到的知识点:泛型,注解。运用的设计模式:工厂模式,适配器模式,单例模式,代理模式。通过适配器模式实现了Retrofit的插件化。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容

  • 简介 刚接触Retrofit的时候,就写了一篇简单的使用介绍:Retrofit 2.0基本使用方法,算是对Retr...
    Whyn阅读 2,823评论 4 24
  • 本文将顺着构建请求对象->构建请求接口->发起同步/异步请求的流程,分析Retrofit是如何实现的。 开始之前,...
    zhuhf阅读 1,604评论 0 10
  • Retrofit是squareup公司的开源力作,和同属squareup公司开源的OkHttp,一个负责网络调度,...
    蓝灰_q阅读 41,187评论 23 281
  • Retrofit这个开源库出来也有一定年头了,记得之前还是在V1.0的版本的时候,之前在三月份也写过一个Retro...
    lovejjfg阅读 1,427评论 0 5
  • 阅读:第二部分(5-6章) @ 2017/4/22 第5章更强的社会联系我们越是更多地一起玩游戏,越是会产生有意识...
    冰洛洛阅读 169评论 0 0