bilibili在线解析接⼝_⼀定能看懂的Retrofit最详细的源码解析!你在使⽤ Retrofit 的时候,是否会有如下⼏点疑惑?
什么是动态代理?
整个请求的流程是怎样的?
底层是如何⽤ OkHttp 请求的?
⽅法上的注解是什么时候解析的,怎么解析的?
Converter 的转换过程,怎么通过 Gson 转成对应的数据模型的?
CallAdapter 的替换过程,怎么转成 RxJava 进⾏操作的?
如何⽀持 Kotlin 协程的 suspend 挂起函数的?
关于 Kotlin 协程请求⽹络,⾸先写⼀个 Demo 来看⼀下协程是怎么进⾏⽹络请求的,然后会再具体分析代码
我会在⽂章中,通过源码,逐步解开疑惑,并且在最后⽂章结尾会再次总结,回答上⾯的⼏个问题。
友情提⽰,本⽂略长但是没有废话,实打实的⼲货,学习需要耐⼼
Retrofit 和 OkHttp 是⽬前最⼴泛使⽤的⽹络请求库了,所以有必要了解它的源码,学习它的优秀的代码与设计,来提升⾃⼰。
本⽂的整体思路
⾸先先看⼀下 Retrofit 的基本⽤法,根据⽰例代码,作为分析源码的依据,以及分析源码的⼊⼝,来⼀步⼀步看⼀下 Retrofit 的⼯作机制。
本⽂的依赖
implementation 'com.squareup.okhttp3:okhttp:4.8.1'
implementation 'fit2:retrofit:2.9.0'
implementation 'fit2:converter-gson:2.5.0'
implementation 'fit2:adapter-rxjava2:2.7.2'
implementation 'de.gson:gson:2.8.6'
implementation 'java3:rxjava:3.0.6'
implementation 'java2:rxandroid:2.1.1'
复制代码
1.什么是Retrofit
HTTP client for Android and Java。⼀个类型安全的 Http 请求的客户端。
Retrofit:A type-safe HTTP client
底层的⽹络请求是基于 OkHttp 的,Retrofit 对其做了封装,提供了即⽅便⼜⾼效的⽹络访问框架。
2.Retrofit的基本⽤法
class RetrofitActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
/
/初始化⼀个Retrofit对象
val retrofit = Retrofit.Builder()
.baseUrl("api.github/")
.ate())
.build()
//创建出GitHubApiService对象
val service = ate(GitHubApiService::class.java)
//返回⼀个 Call 对象
val repos = service.listRepos("octocat")
//调⽤ enqueue ⽅法在回调⽅法⾥处理结果
override fun onFailure(call: Call<List<Repo>?>, t: Throwable) {
t.printStackTrace()
}
override fun onResponse(call: Call<List<Repo>?>, response: Response<List<Repo>?>) {
"de() = ${de()}".logE()
}
})
}
}
复制代码
//⾃⼰定义的 API 请求接⼝
interface GitHubApiService {
@GET("users/{user}/repos")
网站源码在线fun listRepos(@Path("user") user: String?): Call<List<Repo>>
}
复制代码
以上就是 Retrofit 的基本⽤法。
没什么好讲的,写这个例⼦就是为了分析源码做准备,有⼀个源码分析的⼊⼝。
3.源码分析的准备⼯作
先看⼏个表⾯上的类
Builder 类构建,⽐如 CallAdapter、Converter 等Retrofit:总揽全局⼀个类,⼀些配置,需要通过其内部 Builder
GitHubApiService:⾃⼰写的 API 接⼝,通过Retrofit 的 create ⽅法进⾏实例化
OkHttpCall,下⾯会具体说Call:Retrofit 的 Call,是执⾏⽹络请求的是⼀个顶层接⼝,需要看源码中的具体实现类实际是⼀个 OkHttpCall
Callback:请求结果回调
接下来重点来了,进⾏源码分析。
4.源码分析
分析的⼊⼝是我们代码例⼦中的queue(object : Callback<List<Repo>?> {…})⽅法
点进去,看到是 Call 的enqueue⽅法
public interface Call<T> extends Cloneable {
void enqueue(Callback<T> callback);
}
复制代码
这是⼀个接⼝,是我们 GitHubApiService 接⼝中定义的 listRepos ⽅法中返回的 Call 对象,现在就要看GitHubApiService 的初始化,Call 对象是谁。
以及具体返回的是 Call
然后重点就要看 ate(GitHubApiService::class.java) ⽅法,来看下 GitHubApiService 具体是怎么创建的,以及 Call 对象的实现类
5.Retrofit 的 create ⽅法
//Retrofit.java
public <T> T create(final Class<T> service) {
//1
validateServiceInterface(service);
//2
return (T)
new Class<?>[] {service},
new InvocationHandler() {
private final Platform platform = ();
private final Object[] emptyArgs = new Object[0];
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (DeclaringClass() == Object.class) {
return method.invoke(this, args);
}
args = args != null ? args : emptyArgs;
return platform.isDefaultMethod(method)
platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
复制代码
注释 1:这个⽅法,就是验证我们定义的 GitHubApiService 是⼀个接⼝,且不是泛型接⼝,并且会判断是否进⾏⽅法的提前验证
提前验证,为了更好的把错误暴露的编译期,这个不是我们的重点内容,具体代码就不看了。
注释 2 :是⼀个动态代理的⽅法,来返回 GitHubApiService 的实例
动态代理?嗯?什么是动态代理,接下来,我就写⼀个具体的例⼦来展⽰⼀个动态代理的具体⽤法,以及什么是动态代理
先插播⼀段动态代理代码,这个是理解 Retrofit 的⼯作机制所必须的。
6.动态代理的⽰例
6.1.写⼀个动态代理的 Demo
Java 项⽬,模拟⼀个 Retrofit 的请求过程
下⾯是⼀个 Java
//模拟 Retrofit,定义 API 请求接⼝
public interface GitHubApiService {
void listRepos(String user);
}
复制代码
public class ProxyDemo {
//程序的⼊⼝⽅法
public static void main(String[] args) {
//通过动态代理获取 ApiService 的对象
GitHubApiService apiService = (GitHubApiService) wProxyInstance(
ClassLoader(),
new Class[]{GitHubApiService.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("method = " + Name() + " args = " + String(args));
return null;
}
});
System.out.Class());
//调⽤ listRepos ⽅法
apiService.listRepos("octcat");
}
}
复制代码
执⾏ main⽅法
当我们调⽤ apiService.listRepos("octcat");⽅法时,打印出来如下结果
class com.sun.proxy.$Proxy0
method = listRepos args = [octcat]
复制代码
Retrofit 的原理其可以看到当我们调⽤listRepos⽅法的时候,InvocationHandler 的 invoke⽅法中拦截到了我们的⽅法,参数等信息。Retrofit 的原理其实就是这样,拦截到⽅法、参数,再根据我们在⽅法上的注解,去拼接为⼀个正常的OkHttp 请求,然后执⾏。
⽇志的第⼀⾏,在运⾏时这个类⼀个$Proxy0的类。实际上,在运⾏期 GitHubApiService 的接⼝会动态的创建出实现类
实现类也就是这个$Proxy0类,它⼤概长这个样⼦,具体的看鸿洋这篇⽂章 从⼀道⾯试题开始说起 枚举、动态代理的原理
我做了⼀个点改动,⽅便查看,本质上都是⼀样的
class $Proxy0 extends Proxy implements GitHubApiService {
protected $Proxy0(InvocationHandler h) {
super(h);
}
@Override
public void listRepos(String user) {
Method method = Class.forName("GitHubApiService").getMethod("listRepos", String.class);
super.h.invoke(this, method, new Object[]{user});
}
}
复制代码
我们在调⽤listRepos⽅法的时候,实际上调⽤的是 InvocationHandler 的 invoke ⽅法。
6.2总结
在 ProxyDemo 代码运⾏中,会动态创建 GitHubApiService 接⼝的实现类,作为代理对象,执⾏InvocationHandler 的 invoke ⽅法。
动态指的是在运⾏期,⽽代理指的是实现了GitHubApiService 接⼝的具体类,称之为代理
本质上是在运⾏期,⽣成了 GitHubApiService 接⼝的实现类,调⽤了 InvocationHandler 的 invoke⽅法。
什么是动态代理
现在解决了第⼀个疑问:什么是动态代理
好的,动态代理已经知道是啥了,回到我们 ate(GitHubApiService::class.java)⽅法
7.再看 Retrofit 的 create ⽅法
//Retrofit.java
public <T> T create(final Class<T> service) {
validateServiceInterface(service);
return (T)
new Class<?>[] {service},//2
new InvocationHandler() {//3
private final Platform platform = ();
private final Object[] emptyArgs = new Object[0];
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
//4
if (DeclaringClass() == Object.class) {
return method.invoke(this, args);
}
args = args != null ? args : emptyArgs;
//5
return platform.isDefaultMethod(method)
platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
复制代码
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论