【Android】Retrofit源码学习
【Android】Retrofit源码学习
使用Retrofit的流程#
通过Builder创建Retrofit对象:
Copy
Retrofit retrofit = new Retrofit.Builder().baseUrl("").addConverterFactory().build();
用Java注解描述API
Copy
public interface MyApi {
@GET("/api") Call<Data> getData();
}
通过retrofit创建api对象,并建立Call对象
Copy
MyApi api = retrofit.create(MyApi.class);
Call call = api.getData();
通过Call对象获取数据,enqueue()方法发送异步请求,同步方式则使用execute()方法
Copy
call.enqueue(new Callback() {
@Override public void onResponse(Response<ZhuanLanAuthor> author) { System.out.println("name: " + author.getName()); } @Override public void onFailure(Throwable t) { }
});
原理解析#
Retrofit所做的事情:将Java接口翻译成HTTP请求,然后用OkHttp去发送请求。
Retrofit使用动态代理实现了这件事
动态代理#
动态代理可以在不实现相同接口的proxy的情况下,对相关方法进行代理。
Java可以通过Proxy类实现代理模式,而其中的newProxyInstance()方法可以实现动态代理。通过实现InvocationHandler接口来定义代理动作。
Proxy.newProxyInstance(ClassLoader, Class<?>[] interfaces,InvocationHandler)
InvocationHandler的接口定义如下:
Copy
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
参数含义:
proxy:代理对象
method: 代理方法
args: 方法的参数
实现invoke()方法来进行代理:
Copy
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable { // do something method.invoke(target, args); // do something
}
这样便能够成功对target方法进行代理,动态代理生成的代理类的名字为包名+$Proxy+id序号
请求流程分析#
回到使用方法,一开始要使用create()生成API的对象
Copy
MyApi api = retrofit.create(MyApi.class);
这里看下create()的源码:
Copy
public T create(final Class 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 { // 如果是Object的方法则直接调用 if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } // 兼容Java8,Android平台不会调用, 确认平台的方法是通过反射机制判断类的加载信息 if (platform.isDefaultMethod(method)) { return platform.invokeDefaultMethod(method, service, proxy, args); } // 主要方法,返回ServiceMethod对象 return loadServiceMethod(method).invoke(args != null ? args : emptyArgs); } });
}
create使用了动态代理的方法,返回了Proxy.newProxyInstance()动态代理对象
所以api对象为动态代理对象,不是真正的实现接口产生的对象。当api对象调用getData()方法时会被动态代理拦截,然后调用InvocationHandler对象中的invoke()方法。
然后Retrofit通过反射获取到getData()方法的注解信息,配合invoke()的args参数,创建一个ServiceMethod对象
ServiceMethod传入Retrofit对象和Method对象,调用各个接口和解析器,最终生成一个Request,包含api的域名、path、http请求方法、请求头、body等等。最后返回一个Call对象。
Copy
ServiceMethod<?> loadServiceMethod(Method method) {
ServiceMethod<?> result = serviceMethodCache.get(method); // 如果有缓存则直接用 if (result != null) return result; synchronized (serviceMethodCache) { result = serviceMethodCache.get(method); // 线程安全,锁住后查看其他线程是否有加载 if (result == null) { result = ServiceMethod.parseAnnotations(this, method); // 解析注解 serviceMethodCache.put(method, result); // 放入Cache中 } } return result;
}
跟进ServiceMethod.parseAnnotation():
Copy
static ServiceMethod parseAnnotations(Retrofit retrofit, Method method) {
// 解析注解为HTTP请求的相关信息 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) { //API接口方法返回值不能为void throw methodError(method, "Service methods cannot return void."); } return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
这里构建了一个RequestFactory对象,解析了接口中关于Http协议的相关信息,具体解析方法就是拿到Method的Annotation后instansof比较确定
Copy
RequestFactory(Builder builder) {
method = builder.method; baseUrl = builder.retrofit.baseUrl; httpMethod = builder.httpMethod; relativeUrl = builder.relativeUrl; headers = builder.headers; contentType = builder.contentType; hasBody = builder.hasBody; isFormEncoded = builder.isFormEncoded; isMultipart = builder.isMultipart; parameterHandlers = builder.parameterHandlers; isKotlinSuspendFunction = builder.isKotlinSuspendFunction;
}
解析完后使用HttpServiceMethod.parseAnnotations()最后生成HttpServiceMethod对象
Copy
static HttpServiceMethod parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) { boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction; // kotlin支持,先忽略 boolean continuationWantsResponse = false; boolean continuationBodyNullable = false; Annotation[] annotations = method.getAnnotations(); // 方法的注解 @GET @POST @DELETE等 Type adapterType; // ...这里有一段关于Kotlin支持的代码,adapterType adapterType = method.getGenericReturnType(); // 接口方法的返回类型,一般为Call<T> CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method, adapterType, annotations); Type responseType = callAdapter.responseType(); if (responseType == okhttp3.Response.class) { throw methodError(method, "'" + getRawType(responseType).getName() + "' is not a valid response body type. Did you mean ResponseBody?"); } if (responseType == Response.class) { throw methodError(method, "Response must include generic type (e.g., Response<String>)"); } // HEAD请求没有Response Body if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) { throw methodError(method, "HEAD method must use Void as response type."); } // 设置Response的解析,可以是json解析 Converter<ResponseBody, ResponseT> responseConverter = createResponseConverter(retrofit, method, responseType); okhttp3.Call.Factory callFactory = retrofit.callFactory; // 这里若是没有自定则默认为OkHttpClient if (!isKotlinSuspendFunction) { return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter); // 不使用Kotlin就关注这里就行了 } // ...关于Kotlin的return
}
最后返回了HttpServiceMethod的继承类CallAdapted,其中存放着RequestFactory、Converter、CallFactory
然后我们返回来看这段代码
Copy
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
这里调用的invoke方法来为HttpServiceMethod中的invoke方法:
Copy
@Override final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter); return adapt(call, args);
}
// CallAdapted中
@Override protected ReturnT adapt(Call call, Object[] args) {
return callAdapter.adapt(call);
}
这里的OKHttpCall为Okhttp3.Call的封装类,并实现了Call的相关方法enqueue、execute。
这里最后使用的adapt方法调用了Retrofit对象中的callAdapter.adapt()来对Call对象进行了适配。
若是开始初始化Retrofit对象时没有设置CallAdapter,则回默认使用Call,api接口定义时方法的返回类型只能是Call
所以便能解释如下代码:
Copy
Call call = api.getData();
api对象为一个动态代理对象,当执行getData()时进入动态代理函数,在InvocationHandler的invoke函数最后调用了HttpServiceMethod.invoke(args),返回了一个Call对象。
响应流程分析#
Retrofit使用中最后调用自定义的API接口方法返回了Call对象,这个对象实际上是Retrofit自己封装的OkHttpCall对象,随后我们使用enqueue方法发出异步请求
Copy
call.enqueue(new CallBack() {
@Override public void onResponse(Call<MyData> call, Response<MyData> response) { //... on response } @Override public void onFailure(Call<MyData> call, Throwable t) { //... on response }
})
跟进OkHttpCall.enqueue的源码:
Copy
@Override public void enqueue(final Callback callback) {
Objects.requireNonNull(callback, "callback == null"); // callback不能为null okhttp3.Call call; // okhttp3的Call对象 Throwable failure; synchronized (this) { // 线程安全 if (executed) throw new IllegalStateException("Already executed."); executed = true; call = rawCall; // rawCall为OkHttpCall保存的Okttp3的Call对象 failure = creationFailure; if (call == null && failure == null) { try { // createRawCall中使用callFactory.newCall(requestFactory.create(args)) // 实际上就是OkHttpClient.newCall(OkHttp3.Request) // 返回了OkHttp3.Call对象 call = rawCall = createRawCall(); } catch (Throwable t) { throwIfFatal(t); failure = creationFailure = t; } } } if (failure != null) { callback.onFailure(this, failure); return; } if (canceled) { call.cancel(); } // 使用okhttp3.Call的enqueue方法 call.enqueue(new okhttp3.Callback() { @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) { Response<T> response; try { // 这里使用了Converter来解析Response // 将Okhttp3.Response对象解析成Retrofit封装的Response对象 response = parseResponse(rawResponse); } catch (Throwable e) { throwIfFatal(e); callFailure(e); return; } try { // 调用传进来的回调 callback.onResponse(OkHttpCall.this, response); } catch (Throwable t) { throwIfFatal(t); t.printStackTrace(); } } @Override public void onFailure(okhttp3.Call call, IOException e) { callFailure(e); } // 请求失败则进入callback的OnFailure方法 private void callFailure(Throwable e) { try { callback.onFailure(OkHttpCall.this, e); } catch (Throwable t) { throwIfFatal(t); t.printStackTrace(); } } });
}
其中parseResponse()方法:
Copy
Response parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body(); // 将Response Body 和 ResponseHeader 分开 // 之后再对Body进行处理 rawResponse = rawResponse.newBuilder() .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength())) .build(); int code = rawResponse.code(); // HTTP 状态码 // 响应不成功 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(); } } // 响应无内容,填入null if (code == 204 || code == 205) { rawBody.close(); return Response.success(null, rawResponse); } // 保存source的Response Body,在解析失败时可以使用 ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody); try { // 使用responseConverter来解析Body T body = responseConverter.convert(catchingBody); // 将解析好的Body装入Retrofit的Response对象返回 return Response.success(body, rawResponse); } catch (RuntimeException e) { catchingBody.throwIfCaught(); throw e; }
}
主要的parse过程便是,将Okhttp.Response对象的Body和Header拆开,若请求成功且Body有内容则将Body交给responseConverter取解析成响应对象,装入Retrofit的Response对象中返回。
总结#
Retrofit的特色:通过使用注解定义API接口的方式声明API,通过注解的解析,将解析得到的信息封装在RequestFactory中,在使用时调用create()方法生成Okhttp的Request对象。
通过动态代理的方式,代理用户定义的API接口方法,使其生成封装的OkHttpCall对象
封装okhttp.Call为OkHttpCall,使其能够使用CallAdapter(可以使返回的Call对象适配为其他的对象,如RxJava(没用过)中的对象)和ResponseConverter(支持Gson等解析)
目前只读到这里,还有一些机制没读完
参考文章#
https://www.jianshu.com/p/c1a3a881a144
https://segmentfault.com/a/1190000006767113
https://yq.aliyun.com/articles/658544
作者: y4ngyy

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
iOS组件化(一)—Cocopods创建私有库
一、创建一个文件夹 mkdir Module 二、下载工程脚手架 pod lib create AaronSwift AaronSwift是你要创建的组件工程的名称。安装过程中会提示你输入要下载工程的配置(如下:),依次输入:iOS、Swift、Yes、Quick、Yes,其中第二步如果想创建OC库,请输入ObjC。(各版本可能有不同,请根据提示输入) Cloning `https://github.com/CocoaPods/pod-template.git` into `AaronSwift`. Configuring AaronSwift template. ------------------------------ To get you started we need to ask a few questions, this should only take a minute. If this is your first time we recommend running through with the guide: - https://guides.cocoapods.o...
- 下一篇
Java基础知识之—运算符
1. 算术运算符 +,-,*,/,%,++,-- 2. 关系运算符 >,<,>=,<=,==,!= 3. 逻辑运算符 !,&&,&,|,^,|| 4. 赋值运算符 =,+=,*=,/=,-=,%= 5. 位运算符 &,|,^,<<,>>,>>>,~ 6. 条件运算符 ?: 运算符优先级表格
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- CentOS7设置SWAP分区,小内存服务器的救世主
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Windows10,CentOS7,CentOS8安装Nodejs环境
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- CentOS8安装Docker,最新的服务器搭配容器使用