Retrofit 原理解析
Retrofit 是什么?
* Retrofit adapts a Java interface to HTTP calls by using annotations on the declared methods to* define how requests are made. Create instances using {@linkplain Builder* the builder} and pass your interface to {@link #create} to generate an implementation.
Retrofit 是一个对于OkHttp 的增强附件,可以直接通过注解的方式,写网络请求方式(GET,POST),并且具备把返回结果转换成Java对象的扩展能力。
常见写法:
public interface TestService {@GET("api/weather/city/101030100/")Call<WeatherData> getWeather2();public class WeatherData{public String message;public String date;}@GET("api/weather/city/101030100/")Observable<WeatherData> getWeather4();
}
实现原理
1.首先利用Java动态代理技术,根据接口生成一个代理类。
retrofit2.Retrofit#create
public <T> T create(final Class<T> service) {validateServiceInterface(service);return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },new InvocationHandler() {private final Platform platform = Platform.get();private final Object[] emptyArgs = new Object[0];@Override public @Nullable Object invoke(Object proxy, Method method,@Nullable Object[] args) throws Throwable {return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);}});}
2. 每次调用该代理对象的方法的时候,就会走到 invoke方法里。我们会在这个方法里解析注解,拿到请求参数,比如请求方法,参数等信息。
loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
retrofit2.ServiceMethod#parseAnnotations
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);Type returnType = method.getGenericReturnType();if (Utils.hasUnresolvableType(returnType)) {throw methodError(method,"Method return type must not include a type variable or wildcard: %s", returnType);}if (returnType == void.class) {throw methodError(method, "Service methods cannot return void.");}return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);}
3.执行到loadServiceMethod(method).invoke(args != null ? args : emptyArgs);方法的地方:
retrofit2.HttpServiceMethod#invoke
@Override final @Nullable ReturnT invoke(Object[] args) {Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);return adapt(call, args);}
4.然后在OkHttpCall里面,发起真正的网络请求
retrofit2.OkHttpCall#enqueue
@Override public void enqueue(final Callback<T> callback) {call.enqueue(new okhttp3.Callback() {@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {Response<T> response;try {response = parseResponse(rawResponse);} catch (Throwable e) {throwIfFatal(e);callFailure(e);return;}try {callback.onResponse(OkHttpCall.this, response);} catch (Throwable t) {throwIfFatal(t);t.printStackTrace(); // TODO this is not great}}});}
5.将网络返回的数据,根据Convert 转换成对应的接口返回的泛型类型。
如Call <WeatherData>,会把返回结果转成WeatherData 对象。
retrofit2.OkHttpCall#parseResponse
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {ResponseBody rawBody = rawResponse.body();int code = rawResponse.code();if (code < 200 || code >= 300) {try {// Buffer the entire body to avoid future I/O.ResponseBody bufferedBody = Utils.buffer(rawBody);return Response.error(bufferedBody, rawResponse);} finally {rawBody.close();}}ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);try {T body = responseConverter.convert(catchingBody);return Response.success(body, rawResponse);} catch (RuntimeException e) {}}
6.根据接口返回的实参类型,找到对应的实参转换工厂,生成返回值。
如果返回时Call<WeatherData> 则返回Call对象,如Observable<WeatherData> 则返回Observable对象。
如果是Call对象,则对应的Adapter 是:
retrofit2.DefaultCallAdapterFactory#get
return new CallAdapter<Object, Call<?>>() {public Type responseType() {return responseType;}public Call<Object> adapt(Call<Object> call) {return (Call)(executor == null ? call : new DefaultCallAdapterFactory.ExecutorCallbackCall(executor, call));}};
如果返回是Observable,那么是:
hu.akarnokd.rxjava3.retrofit.RxJava3CallAdapter#adapt
@Override public Object adapt(Call<R> call) {Observable<Response<R>> responseObservable = isAsync? new CallEnqueueObservable<>(call): new CallExecuteObservable<>(call);Observable<?> observable;if (isResult) {observable = new ResultObservable<>(responseObservable);} else if (isBody) {observable = new BodyObservable<>(responseObservable);} else {observable = responseObservable;}return RxJavaPlugins.onAssembly(observable);}
最终RxJava将结果返回给调用的地方。
@Override public void onNext(Response<R> response) {if (response.isSuccessful()) {observer.onNext(response.body());}}
反射获取返回类型:
method.getGenericReturnType()
这个方法是返回的一个全类型,比如对于 Observable<WeatherData> getWeather4(); 返回值是下面截图中的类型:
我们可以根据返回的总类型,拿到返回的泛型类型:
ParameterizedType typeType[] types = type.getActualTypeArguments();
比如对于 Observable<WeatherData> getWeather4(); 我们可以先根据method.getGenericReturnType() 拿到整个的返回类型,然后调用 getActualTypeArguments 方法拿到泛型类型WeatherData
总结:
单一职责:
如果我需要一个功能,那么暴露接口出去,让别人实现,这就具备了可拓展性。比如说结果转换,返回结果的工厂。Retrofit只负责整个框架各个部门工作起来。
结果转换
T body = responseConverter.convert(catchingBody);return Response.success(body, rawResponse);
CallAdapted 负责返回类型的转换
反射和注解
retrofit2.OkHttpCall 是真正的调用okhttp 的地方。
retrofit2.RequestFactory#create 负责生成请求的参数
Q:为什么要这样写:
public <T> T create(final Class<T> service) { 而不是public <T> T create(final Class service) {
抓取Retrofit 的真实Http请求
我们使用Retrofit 之后,代码写起来方便了,但是调试起来可能不太方便。
比如我们想要看Retrofit最终发出的Http Get请求的全链接,那应该在哪里看呢?
这个需要熟悉Retrofit 原理,最终会走到OkhttpCall里面。
retrofit2.OkHttpCall#createRawCall
在这个方法里面加断点,就可以看到发起请求的全链接,然后在浏览器里面查看,调试。
Retrofit 原理解析相关推荐
- Android进阶:七、Retrofit2.0原理解析之最简流程【上】
retrofit 已经流行很久了,它是Square开源的一款优秀的网络框架,这个框架对okhttp进行了封装,让我们使用okhttp做网路请求更加简单.但是光学会使用只是让我们多了一个技能,学习其源码 ...
- Retrofit原理分析
Retrofit原理分析 温故而知新 还记得retrofit的使用方法嘛,下面我们来回顾一下 接口定义 public interface GitHubService {@GET("users ...
- Retrofit2 工作原理解析(一)
Retrofit2 工作原理解析(一) 概述 Retrofit是square公司开源的一款类型安全的http请求框架,用于Java和Android程序.Retrofit可以说是restful风格的一个 ...
- Spark Shuffle原理解析
Spark Shuffle原理解析 一:到底什么是Shuffle? Shuffle中文翻译为"洗牌",需要Shuffle的关键性原因是某种具有共同特征的数据需要最终汇聚到一个计算节 ...
- 秋色园QBlog技术原理解析:性能优化篇:用户和文章计数器方案(十七)
2019独角兽企业重金招聘Python工程师标准>>> 上节概要: 上节 秋色园QBlog技术原理解析:性能优化篇:access的并发极限及分库分散并发方案(十六) 中, 介绍了 ...
- Tomcat 架构原理解析到架构设计借鉴
点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 Tomcat 架构原理解析到架构设计借鉴 Tomcat 发展这 ...
- 秋色园QBlog技术原理解析:性能优化篇:数据库文章表分表及分库减压方案(十五)...
文章回顾: 1: 秋色园QBlog技术原理解析:开篇:整体认识(一) --介绍整体文件夹和文件的作用 2: 秋色园QBlog技术原理解析:认识整站处理流程(二) --介绍秋色园业务处理流程 3: 秋色 ...
- CSS实现元素居中原理解析
原文:CSS实现元素居中原理解析 在 CSS 中要设置元素水平垂直居中是一个非常常见的需求了.但就是这样一个从理论上来看似乎实现起来极其简单的,在实践中,它往往难住了很多人. 让元素水平居中相对比较简 ...
- 秋色园QBlog技术原理解析:Web之页面处理-内容填充(八)
文章回顾: 1: 秋色园QBlog技术原理解析:开篇:整体认识(一) --介绍整体文件夹和文件的作用 2: 秋色园QBlog技术原理解析:认识整站处理流程(二) --介绍秋色园业务处理流程 3: 秋色 ...
最新文章
- 今天清华学长手把手带你做UI自动化测试
- 9.11排序与查找(三)——给定一个排序后的数组,包括n个整数,但这个数组已被旋转过多次,找出数组中的某个元素...
- 检查CentOS7定时任务是否启用并执行过
- php array 取值 没有key,PHP array_key_exists不起作用;数组不是多维的
- linux虚拟化技术这么玩,Linux上实现虚拟化技术的优势
- CurrentUser获取不到当前登录用户name
- POJ 3009 Curling 2.0【带回溯DFS】
- python-opencv 角点检测的 FAST 算法
- 谁是小米真正的友商——小米中国受让专利来源分析
- 剑指offer T32及其变种从上到下打印二叉树(之字型打印)
- 密集芯片的焊接技巧:从LQFP64说起
- UHL IOL NVMe测试工具安装及使用的常见问题
- Android WiFi only配置
- 如何在手机上访问自己写的网页?
- matlab三维立体图
- 金地集团三季报:归母净利润同比降超三成,仍存债务压力
- 行人重识别 (Re-ID)数据集介绍
- html实现用户调查的表单网页,江苏开放大学网页制作基础及HTML测试作业二制作1个E游调查的表单网页...
- 修复 Windows 映像
- Matlab放烟花 带音效哟 祝大家新年快乐
热门文章
- http的“无连接”指的是_【38期】一份tcp、http面试指南,常考点都给你了
- 10、计算机图形学——几何介绍(曲面的分类以及示例)
- 5.QML动画——分组动画
- C++知识点4——vector与string简述
- 一种近似方法将场地坐标转为像素坐标
- ubuntu系统声音_今日热闻 | 小米11有望首发骁龙875、折叠iPhone测试、新规禁止网购忽悠打折、印度真米粉、M1 Mac运行Ubuntu...
- 超详细 Nginx 极简教程,傻瓜一看也会!
- 递归算法转换为非递归算法的技巧
- VMware下Windows2003R2虚拟机磁盘扩容方法
- 第十二周项目1-阅读程序(三)