文章目录
一.参考博客
三方库源码学习-1 :OkHttp
一定能看懂的 Retrofit 最详细的源码解析!
三方库源码笔记(7)-Retrofit 源码详解
又看一遍Retrofit源码,这次写了篇笔记
二.Retrofit的介绍
官方介绍: A type-safe HTTP client for Android and Java. 这说明 Retrofit 的内部实现并不需要依赖于 Android 平台,而是可以用于任意的 Java 客户端,Retrofit 只是对 Android 平台进行了特殊实现而已。
使用:
可以参考官网:Retrofit
看我之前的博客:Andrioid网络请求—— Retrofit的简单使用
这里给出一个小例子:
版本基于2.9.0
```java
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
public class RetrofitRequest {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
GitHubService service = retrofit.create(GitHubService.class);
Call<List<Repo>> repos = service.listRepos("octocat");
}
三.什么是动态代理
在介绍Retrofit之前,先插播一下动态代理。
动态 指的是在运行期,而 代理 指的是实现了接口的类,实现了接口的方法,称之为代理。有时候,对于某个既定的interface,我们不希望直接声明并使用其实现类,而是希望实现类可以动态生成,此时就可以通过 Proxy.newProxyInstance 来实现目的。
看一个简单的代理模式的例子。
interface FaceDemo {
fun run(user : String)
}
fun main(args: Array<String>) {
val request = Proxy.newProxyInstance(
FaceDemo::class.java.classLoader,
arrayOf<Class<*>>(FaceDemo::class.java),
object : InvocationHandler{
override fun invoke(proxy: Any?, method: Method?, args: Array<out Any>?): Any {
return println("method = ${method?.name} args : ${args?.get(0)} ")
}
}
) as FaceDemo
println(request.javaClass)
//调用方法
request.run("liHua")
}
运行结果:
可以看到:
- InvocationHandler.invoke() 方法拦截了我们调用的接口中的方法。
- 在运行时这个类是一个 $Proxy0 的类。
实际上通过代理模式,我们定义的接口会动态的创建出实现类也就是 $Proxy0 类,它大概长下面这个样子。
class $Proxy0 extends Proxy implements FaceDemo {
protected $Proxy0(InvocationHandler h) {
super(h);
}
private static Method m3;
static
{
m3 = Class.forName("FaceDemo").getMethod("FaceDemo", new Class[] {
Class.forName("java.lang.String"),
});
}
@Override
public void run(String user) {
/* h就是我们自己创建的InvocationHandler,所以最终就回调到
它里面的invoke方法内执行
*/
super.h.invoke(this, m3, new Object[]{
user});
}
}
四. Retrofit.Create()方法
从 create() 方法往下深入。
```java
public <T> T create(final Class<T> service) {
validateServiceInterface(service); // 1
return (T) //2
Proxy.newProxyInstance(
service.getClassLoader(),
new Class<?>[] {service},
new InvocationHandler() {
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
......
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
注释1:这个是用来验证我们定义的GitHubService是一个接口,且不是泛型接口,并且会判断是否进行提前验证,提前验证可以更好的把错误暴漏在编译器,但是比较耗时,可能造成卡顿。
注解2:这里其实就是用了动态代理来处理的。借助动态代理拿到接口的实现类,当调用接口的方法时,会回调到它里面的 invoke() 方法。并在 invoke() 方法中拿到声明listRepos() 时标注的各个配置项。
这个方法的关键代码就是loadServiceMethod(method).invoke(args) 。主要逻辑就是把method对象转换为ServiceMethod对象,并做缓存。在下次使用相同的请求方法时,直接从缓存池中取ServiceMethod对象,优化了性能。
//1
private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
ServiceMethod<?> loadServiceMethod(Method method) {
ServiceMethod<?> result = serviceMethodCache.get(method);
//2
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
//3
result = ServiceMethod.parseAnnotations(this, method);
//4
serviceMethodCache.put(method, result);
}
}
return result;
}
注解1:创建一个Map集合,把ServiceMethod对象缓存起来,因为同一个请求方法可能会被调用多次,缓存提升性能。
注解2:如果该方法已经被缓存过了,直接用原来缓存的ServiceMethod
注解3:将每个代表接口方法的 method 对象转换为 ServiceMethod 对象,该对象中就包含了接口方法的具体信息。
注解4:把拿到的ServiceMethod对象缓存进集合中。
五. ServiceMethod
刚才的loadServiceMethod(method) 方法返回的就是一个ServiceMethod。它是一个抽象类,主要的逻辑如下:
- 拿到 RequestFactory对象,这个是用来解析注解的。后面再讲。
- 通过HttpServiceMethod.parseAnnotations 来获取ServiceMethod的实现类。
这里运用了工厂模式,由于最终的网络请求方法可能是多种多样的,既可以通过线程池来执行,又可以通过Kotlin协程来执行。使用工厂模式就可以把这种差异隐藏在不同的ServiceMethod实现类里。而外部都是通过parseAnnotations来获取实现类。
abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
//1 这里拿到了requestFactory对象,它是用来解析注解的
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
.......
//2 使用工厂模式拿到ServiceMethod实现类
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
abstract @Nullable T invoke(Object[] args);
}
注意这里还有一个抽象方法 invoke ,而在刚才动态代理的invoke方法中,最终调用的就是一个invoke方法,所以这个方法的实现很关键。
六. 初看HttpServiceMethod
HttpServiceMethod 是 ServiceMethod的唯一直接子类。而它本身也是一个抽象类。我们先顺着刚才的思路往下走,等会在来看这个类。
现在主要看一下 invoke 方法。主要的逻辑是:
- 创建OkHttpCall对象。这是实际进行网络请求的类。
- 把刚才拿到的 Call < ResponseT > 对象通过adapt进行适配为我们需要的Call并返回。
```java
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
我们先看OkHttpCall这个类。
七. OkHttpCall
这个类是 retrofit2.Call 的实现类,是真正发起OkHttp请求的地方。当我们调用 call.enqueue(Callback) 方法时,最终就会调用到这里的OkHttpCall.enque方法。
- OkHttpCall.enqueue
@Override
public void enqueue(final Callback<T> callback) {
okhttp3.Call call;
call = rawCall;
failure = creationFailure;
if (call == null && failure == null) {
//1:创建了okhttp3.Call call
call = rawCall = createRawCall();
}
//调用的是okHttp3.call.enqueue,所以这里的代码是发生在OkHttp中的
call.enqueue(
new okhttp3.Callback() {
@Override
public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
//2 :对拿到的结果进行解析
response = parseResponse(rawResponse);
//成功之后的回调
callback.onResponse(OkHttpCall.this, response);
}
//失败的回调
@Override
public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}
private void callFailure(Throwable e) {
callback.onFailure(OkHttpCall.this, e);
}
});
}
这个方法的主要逻辑就是创建出OkHttp的Call,并调用它的enqueue方法发起请求。最后对响应结果进行处理。并调用回调接口把结果返回。
- OkHttpCall.execute
public Response<T> execute()