
阅读 Retrofit 源码

Retrofit 简介
Retrofit 是 Square 公司开发的一款针对 Android 和 Java 的类型安全的网络请求框架。
官网说的是:A type-safe HTTP client for Android and Java
type-safe(类型安全):一个框架类型安全指的是它会在编译期间就将类型错误,不会在运行时报类型错误。
所以他会有大量的类型检查,在编译期间
OkHttp 和 Retrofit 的区别,Retrofit 是 OKHttp 的功能细分,Retrofit 实现网络请求更便携,相当于 Square 帮你把很多代码提前写好了,但 OKHttp 更灵活
源码开读
以下我使用的是 Retrofit 2.11.0
不同版本有些许差异,但我只以 2.11.0
为例
首先我们从 Retrofit.create()
开始读
1 | public <T> T create(final Class<T> service) { |
总体他一共就两行代码,第一行是 this.validateServiceInterface(service);
,第二行是 return Proxy.newProxyInstance(...)
下面的都是他的参数
validateServiceInterface
(验证)
首先我们看 this.validateServiceInterface(service);
1 | private void validateServiceInterface(Class<?> service) { |
一开始它进行了
service.isInterface()
的判断,这个service
就是我们在调用Retrofit.create()
传入的参数,也就是我们自己声明的接口,比如:1
2
3
4interface GitHubService {
fun listRepos(: Call<List<Repo>> user: String?)
}- 为什么要判断这个是不是接口呢?因为
Retrofit
只允许你声明接口,这是它的设计意图,也是后面使用动态代理的条件
- 为什么要判断这个是不是接口呢?因为
后面它在确认你声明的是接口之后,生成了一个叫
check
的Deque
(双端队列),紧接着进行了一个while
循环,判断条件是当check
为空的时候结束循环。- 这个循环里它先将
check
的第一个元素取出,判断它有没有泛型类型参数(详见我的泛型文章),因为泛型会类型擦除,导致动态代理的时候没办法生成具体的类型,会影响 HTTP 的响应和类型转换。
- 这个循环里它先将
Collections.addAll(check, candidate.getInterfaces());
是在判断完当前接口之后,将它直接实现的接口放进check
里面。依次判断,直到check
为空。下面是判断
validateEagerly
(提前验证、提前确认) ,这是个控制开发者声明的接口什么时候初始化的一个开关- 默认
validateEagerly = false
开发者声明的接口方法会在首次调用的时候调用loadServiceMethod
方法,但如果将validateEagerly
设为true
,那就会在调用Retrofit.create()
的时候进行loadServiceMethod
- 由于
loadServiceMethod
内部实现涉及到反射,所以集中将所有声明的接口方法初始化会可能会导致性能问题 - 但开启
validateEagerly
可以在调用方法之前,进行检查,这样避免在调用方法的时候再发现问题,方便测试或者提前处理异常,对稳定有帮助
- 默认
OK!这样我们就看完了 validate
的流程,接下来该看 newProxyInstance
(动态代理)了
newProxyInstance
(动态代理)
动态代理可能对于部分人有些陌生
我觉的有必要从代理模式来讲解
静态代理
代理模式(Proxy Pattern)是一种结构型设计模式,它通过为目标对象(真实对象)提供一个代理对象,以控制对目标对象的访问。代理对象与真实对象实现相同的接口,调用代理对象的方法时,实际上可以在内部做一些额外的处理,然后再调用真实对象的方法。
所以,有一个实际的类,它的方法需要被隔离或者扩展,所以生成一个代理类,这个类的方法签名(函数名和参数列表)和实际的类一致,调用这个代理类的方法来影响实际类的方法。
也就是说,你想调用一个方法 RealImage.displsy()
,也就是想让 RealImage
显示在屏幕上。可是你又想让它在现实的时候,做一些其他的操作。
此时你就可以写一个代理类 ProxyImage
这个类和 RealImage
一样,都实现了同一个接口,或者干脆 ProxyImage
继承 RealImage
,或者更干脆一点,两个类的函数签名(函数名和参数列表)一致就行。
注意
保持的继承关系可以让代码在结构上更稳定,索然让两个类的函数签名一致也可以达到代理的目的,但是有继承关系的代码更加稳定
1 | interface Image { |
输出结果:
1 | Loading wallpaper.png |
你会发现,在 Main
函数里,你使用了 ProxyImage
但却最终实际上调用了 RealImage
的 display()
,这就是代理模式中的静态代理
那么动态代理呢?
动态代理
和静态代理类似,动态代理是在运行的时候,生成 ProxyImage
来代理 ReadImage
处理一些代码逻辑。
1 | interface Image { |
同样,输出结果如下:
1 | Loading wallpaper.png |
动态代理也是一样,用一个代理类来代理实际的对象,可以看到在 Main
函数中也是用了 Proxy.newProxyInstance
第一个参数是需要一个能够加载需要被代理的接口的 ClassLoader
,一般使用需要代理的接口的类加载器就可以。第二个参数是我们要代理的接口 Class
对象,第三个就是代理的核心逻辑 InvocationHandler
使用哪个 ClassLoader ?
- ClassLoader 一般只要使用
MyInterface.class.getClassLoader()
就行了- 但由于一些其他的特殊情况,使用其他的
ClassLoader
也是有可能的,比如:你不知道要代理的类是来自哪里,你可以使用Thread.currentThread().getContextClassLoader()
- 为什么 java 就不能将
ClassLoader
默认赋给你,而是要你显式传入呢?
- 这就涉及到 java
ClassLoader
的设计哲学了,这里就不再岔开话题,想了解的移步隔壁 java ClassLoader 哲学
但这段代码确实对于刚接触的人来说有点陌生,到底是怎么代理呢?我们直接输出这个动态生成的类,一探究竟
我们切到 java8 使用 sun.misc.ProxyGenerator
来输出这个动态代理生成的类
1 | import sun.misc.ProxyGenerator; |
这是用来生成动态代理生成类的工具类
关于贴源码的提示
我一直认为贴出
import
是很重要的,因为 java 里也很有很多重复的同名类名,贴出来import
可以帮阅读者
1 | public final class ImageDynamicProxy extends Proxy implements Image { |
可以看到,这个动态生成的类,继承了 Proxy
类,实现了 Image
接口,并且重写了接口的所有方法
在最下面有一个 static
代码块,在类加载时自动执行一次,初始化了里面的所有方法(equals
,display
,toString
,hashCode
)的 Method
静态对象
在重写的每个接口的方法里,主要方法内容都是 super.h.invoke
,也就是 InvocationHandler.invoke()
所以对于所有的方法都会调用 invoke
,如果你要在遇到不同的方法时处理不同的逻辑,就在 invoke
的实现里可以使用 switch-case
对不同的方法进行不同的实现
这就是所有动态代理的内部原理
- 代理模式的主要意义:
- 控制访问
代理对象可以对客户端的请求进行拦截和控制。比如,可以在调用真实对象的方法之前进行权限校验、延迟加载、日志记 录或事务控制等操作,从而增加额外的安全性和灵活性。 - 解耦与增强扩展性
通过引入代理层,可以将一些横切关注点(例如日志记录、缓存、远程通信等)从核心业务逻辑中分离出来,降低系统耦 合度,增强代码的可维护性和扩展性。 - 统一接口
无论是直接访问真实对象,还是通过代理对象访问,都对客户端透明。客户端只需依赖接口,不必关心对象是代理还是具 体实现,简化了程序设计和后期维护。
- 控制访问
继续看 Retrofit
newProxyInstance
在
newProxyInstance
中,声明了一个emptyArgs
这个一看就是要在args
为null
的时候,传入的方法参数(来自第 11 行最后面)在
invoke
方法里,使用getDeclaringClass
判断这个方法的声明类是不是Object
声明的方法,也就是toString()
HashCode()
这类函数,如果是的话就直接调用而后是一个
Reflection
对象,通过Platform.reflection
来获得,这个其实很好理解我们看下里面的代码实现:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34final class Platform {
static final Executor callbackExecutor;
static final Reflection reflection;
static final BuiltInFactories builtInFactories;
static {
switch (System.getProperty("java.vm.name")) {
case "Dalvik":
callbackExecutor = new AndroidMainExecutor();
if (SDK_INT >= 24) {
reflection = new Reflection.Android24();
builtInFactories = new BuiltInFactories.Java8();
} else {
reflection = new Reflection();
builtInFactories = new BuiltInFactories();
}
break;
case "RoboVM":
callbackExecutor = null;
reflection = new Reflection();
builtInFactories = new BuiltInFactories();
break;
default:
callbackExecutor = null;
reflection = new Reflection.Java8();
builtInFactories = new BuiltInFactories.Java8();
break;
}
}
private Platform() {}
}Platform
顾名思义就是平台,里面的reflection
是一个 Android api 等级的对象,通过判断java.vm.name
来获得,也就是说这是个判断你使用的是哪个 Android 版本的对象最后这个
return
里面是一个判断,如果reflection.isDefaultMethod(method)
为true
,就返回reflection.invokeDefaultMethod(method, service, proxy, args)
否则就返回loadServiceMethod(service, method).invoke(proxy, args);
我们先看reflection.isDefaultMethod(method)
这里一共只有三种reflection
分别是Android24
Reflection
和Java8
,我们一个个看Android24
1
2
3
4
5
6
7static final class Android24 extends Reflection {
boolean isDefaultMethod(Method method) {
return method.isDefault();
}
......
}这个方法调用的是用于判断是不是接口声明时候的实现的
default
方法Reflection
1
2
3
4
5
6class Reflection {
boolean isDefaultMethod(Method method) {
return false;
}
......
}这里直接返回了
false
Java8
1
2
3
4
5
6
7
8// Only used on JVM.
static class Java8 extends Reflection {
boolean isDefaultMethod(Method method) {
return method.isDefault();
}
......
}这里也是直接判断是不是接口实现的
default
方法method.isDefault()
从 Java 8 开始,接口(interface)中可以包含带有实现的方法,这种方法通过关键字 default 声明。例如:
1
2
3
4
5
6// Only used on Android API 24+.
public interface MyInterface {
default void sayHello() {
System.out.println("Hello from default method!");
}
}这个就是用来判断是不是接口声明的时候,写的
default
方法所以你应该就明白了,就是判断是不是支持 java8 (原生 Android api 24 开始支持 java8 特性),支持就判断是不是接口的
default
方法,不支持,那就不可能是接口的default
方法,干脆直接返回false
提示
- 如果你在看过其他的 Retrofit 源码,你可能会发现有一个
hasJava8Types
的字段,其实效果是一样的,都是为了判断是否有接口的default
实现
- 如果你在看过其他的 Retrofit 源码,你可能会发现有一个
我们继续看,当判断了接口里有默认实现,我们这里就直接调用
invokeDefaultMethod
方法,这个方法又是什么呢?
我们还是看看实现,这次我们直接放结论,如果是 Reflection,就直接抛出AssertionError
因为他没法声明default
方法,如果是Java8
或者Android24
就直接使用DefaultMethodSupport.invoke
调用default
方法,也就是说,Retrofit
会认为你自己实现好了方法调用逻辑而不会帮你生成内部实现。最后,如果你没有接口的
default
实现,那么就轮到Retrofit
来帮你实现了,也就是最后的loadServiceMethod
loadServiceMethod
我们看到最后一行,loadServiceMethod(service, method).invoke(proxy, args);
这里调用了两个方法,第一个 loadServiceMethod
返回一个 ServiceMethod
,然后调用 ServiceMethod
的 invoke
方法,我直接进去看看源码
1 | ServiceMethod<?> loadServiceMethod(Class<?> service, Method method) { |
- 我们发现这个
loadServiceMethod
方法总体来说就是返回了一个ServiceMethod
,我们先看它怎么实现的,再看invoke
- 这个方法里是一整个
while
循环 - 先是在
serviceMethodCache
里取出一个Object
- 如果这个
Object
的类型是ServiceMethod
,那就说明这个方法就已经被加载了,就会直接返回这个对象。 - 如果它是空的,那就说明方法还没被加载,就会
new
一个Object lock
- 然后紧接着我们对这个
lock
加锁,调用putIfAbsent
将这个method
作为key
放进去,value
是lock
,再次判断lookup
为空(这里putIfAbsent
放进去method
之后,如果之前没有这个key
就会返回null
,然后使用if (lookup == null)
所以这里不仅进行了双重锁检验还将method
放进去了,value
是lock
) - 然后
result = ServiceMethod.parseAnnotations(this, service, method);
生成一个名为result
的ServiceMethod
的对象,也就是初始化这个方法。 - 如果这里
catch
到问题,会把刚才添加进去的method
移除掉 - 如果初始化成功,就更新缓存,也就是将刚才初始化的
result
放进serviceMethodCache
里面
- 然后紧接着我们对这个
- 如果这个
寻找 invoke
看明白可这个方法我们先回过头看看
invoke
1
abstract T invoke(Object instance, Object[] args);
发现他就是一个抽象方法,没有实现,那我们就得找找这个类的实现了,所以继续看
loadServiceMethod
返回的对象,也就是最后的那个ServiceMethod.parseAnnotations
ServiceMethod.parseAnnotations
进入这个源码我们发现,他和 invoke
在一个类里实现,那我们看 ServiceMethod.parseAnnotations
它内部是怎么实现的
1 | static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Class<?> service, Method method) { |
这个方法很简单,我们一步步看
一开始生成了一个
RequestFactory
这个就是来生成 HTTP 请求报文的
简单看一下这个类,里面使用了Builder
,并且有一些分析注解的方法getGenericReturnType
是在方法的获取返回类型然后判断这个
returnType
是否是没法处理的类型,我们看看它内部实现1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30static boolean hasUnresolvableType( { Type type)
if (type instanceof Class<?>) {
return false;
}
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
for (Type typeArgument : parameterizedType.getActualTypeArguments()) {
if (hasUnresolvableType(typeArgument)) {
return true;
}
}
return false;
}
if (type instanceof GenericArrayType) {
return hasUnresolvableType(((GenericArrayType) type).getGenericComponentType());
}
if (type instanceof TypeVariable) {
return true;
}
if (type instanceof WildcardType) {
return true;
}
String className = type == null ? "null" : type.getClass().getName();
throw new IllegalArgumentException(
"Expected a Class, ParameterizedType, or "
+ "GenericArrayType, but <"
+ type
+ "> is of type "
+ className);
}- 第一个判断,是判断这个类型是不是
Class
类型,如果是就返回false
,也就是没有无法处理的类型 - 第二个判断,是判断是否是
ParameterizedType
也就是泛型类型,如果是就进入循环,进入泛型类型参数里递归检查类型是否是不可处理的,只要有一个不可处理,就返回true
。 - 第三个判断,泛型数组,取出泛型类型,递归判断这个泛型类型是否不可处理,也就是回到了第二个判断
- 第四个判断,类型变量,也就是泛型类型参数类型,就返回
true
。 - 第五个判断,通配符类型,也就是
?
,? extends
,? super
,这种也不能判断,所以返回true
- 最后如果以上判断都没有,就最后抛出异常,提示需要以上类型中的一个
- 第一个判断,是判断这个类型是不是
继续回看
parseAnnotations
,判断返回类型是否为void
类型,如果就是就抛出异常“不允许返回 void”最后返回
HttpServiceMethod.parseAnnotations
,我们继续查看HttpServiceMethod
发现他继承了ServiceMethod
类似,也是一个抽象类。所以最后还是又套了一层,调用了
HttpServiceMethod.parseAnnotations
那我们继续看HttpServiceMethod
吧
我们进入HttpServiceMethod.parseAnnotations
这个方法之后太长了,我们先看有没有简单的,比如invoke
找到 invoke
HttpServiceMethod
确实有实现 invoke
方法
1 |
|
- 这个方法是创建饿了一个
Call
而且还是一个OkHttpCall
我们简单看一下,它实现了Call
接口,如果你看过OkHttp
的源码, 这里应该会感觉很熟悉,我们后面再分析,再继续看invoke
- 然后调用了
adapt
方法,那adapt
方法又是怎么实现的,我们继续看
寻找 adapt
1 | protected abstract ReturnT adapt(Call<ResponseT> call, Object[] args); |
又是抽象方法,所以我们需要像找 invoke
一样找找这个 HttpServiceMethod
的具体实现了,回去继续看它的 HttpServiceMethod.parseAnnotations
HttpServiceMethod.parseAnnotations
1 | static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations( |
这个方法确实有点长,我们粗略看一下,我们直接找 return
,也就是看看他到底是怎么返回一个 HttpServiceMethod
的
也就是最后一段:
1 | if (!isKotlinSuspendFunction) { |
也就是说,这里通过判断是否是 suspend
方法来生成对应的 HttpServiceMethod
,既然是 suspend
方法,那肯定也得生成 suspend
方法啊,这是对于 kotlin
协程的适配
我们直接看对于普通方法的实现,这篇文章就先不管 suspend
方法,我们直接看 CallAdapted
找到 adapt
1 | static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> { |
这个 CallAdapted
实现了 HttpServiceMethod
并且实现了 adapt
注意
CallAdapted
的含义就是被适配的Call
,很多英语层面的含义还是可以看出来一些代码的设计意图的
然后我们此时可以继续往源码内部深入,找到 retrofit.callAdapter
,Retrofit
类里面有一个 callAdapterFactories
而这个 callAdapterFactories
会在 Retrofit
的构造函数里初始化,然后我们想到 Retrofit
我们平时不都是 build
出来的吗?!就像这样
1 | val retrofit = Retrofit.Builder() |
然后我们发现这文件里确实有 build
方法,这里一下子就串起来了。
我们继续深入挖掘,找找这个 callAdapterFactories
是这么初始化的,找到 DefaultCallAdapterFactory
,并发现如下代码
1 | return new CallAdapter<Object, Call<?>>() { |
然后大致就知道这个就是返回一个 Call
的实例(在这里是 ExecutorCallbackCall
),返回看代码注释里写的就是
闭环了
所以我们挖了这么久回头梳理一下,就是要搞明白 loadServiceMethod(service, method).invoke(proxy, args)
这行代码最终干了什么————就是返回了一个 ExecutorCallbackCall
loadServiceMethod
会返回一个CallAdapted
,这个CallAdapted
继承了HttpServiceMethod
- 返回他之后,会调用
invoke
,这个invoke
会调用adapt
,最终调用AdapterFactory
的get
返回一个ExecutorCallbackCall
- 总结就是动态代理的
InvocationHandler
的invoke
方法会返回一个ExecutorCallbackCall
,也就是我们写的val service = retrofit.create(GitHubService::class.java)
的service
里面会调用invoke
并返回一个ExecutorCallbackCall
- 我们看看
ExecutorCallbackCall
这个方法里面也有enqueue
那么既然动态代理就是为了生成这个ExecutorCallbackCall
是不是就意味着这个enqueue
就是我们开发的时候写的那个enqueue
————还真是!!!! - 我们看看这个
enqueue
实现了什么吧
1 | public Call<Object> adapt(Call<Object> call) { |
- 这个
delegate
就是我们一开始调用adapt
填入的那个Call
,也就是OkHttpCall
,一会儿我们再看OkHttpCall
我们先把这个看完 - 也就是说这个
ExecutorCallbackCall
把这个OkHttpCall
包了一层 - 这个
ExecutorCallbackCall
的enqueue
里面使用了一个Executor
切了线程,并调用了callback
的onFailure
和onResponse
(也就是开发时候写的callback
) - 这里切线程是有点奇怪的,因为如果最终使用的是
OkHttp
的enqueue
,那就没有必要在这里切线程了,所以我们再深挖一下,看看这个callbackExecutor
里面是怎么操作的 - 我们找到这个
callbackExecutor
是在 Retrofit 的构造方法里初始化的callbackExecutor = Platform.callbackExecutor;
点进去发现是这样的
1 | static { |
又是熟悉的代码,我们看看这个
AndroidMainExecutor
的实现1
2
3
4
5
6
7
8
9
10final class AndroidMainExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
AndroidMainExecutor() {
}
public void execute(Runnable r) {
this.handler.post(r);
}
}这里就看出来,原来没有切线程,而是在主线程里,这是再往前台切线程
所以这就是为什么 Retrofit 的callback
里面的代码可以更新界面(Android 更新界面需要在主线程)
所以这个 adapt
的作用还有将线程切回主线程的作用
回看 OkHttpCall
然后我们继续返回 HttpServiceMethod
里面回看 invoke
里的 OkHttpCall
注意
这个
OkHttpCall
和Call
都是Retrofit
里面的,并非OkHttp
里面的
我们挑一个关键函数看,比如经常使用的 enqueue
1 | public void enqueue(final Callback<T> callback) { |
代码有点长,但其实并不复杂,做了一些判断,然后调用
createRawCall
创建一个okhttp3.Call
哎!!(キ`゚Д゚´)!!最终还是调用了okhttp3.Call
创建成功就是调用
call.enqueue
也就是我们自己写OkHttp
的时候使用的enqueue
,写个Callback
接收Response
。我们可以发现,有一个
response = OkHttpCall.this.parseResponse(rawResponse);
也就是说 Retrofit 帮你处理了rawResponse
并不是直接丢给你,具体怎么处理的一看就懂,这里贴一下代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
rawResponse = rawResponse.newBuilder().body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength())).build();
int code = rawResponse.code();
if (code >= 200 && code < 300) {
if (code != 204 && code != 205) {
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try {
T body = (T)this.responseConverter.convert(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
catchingBody.throwIfCaught();
throw e;
}
} else {
rawBody.close();
return Response.success((Object)null, rawResponse);
}
} else {
Response e;
try {
ResponseBody bufferedBody = Utils.buffer(rawBody);
e = Response.error(bufferedBody, rawResponse);
} finally {
rawBody.close();
}
return e;
}
}里面有一个比较关键的对象
responseConverter
它刚才我们就见过,在
OkHttpCall
被创建的时候,再往上追溯会在HttpServiceMethod.parseAnnotations
里找到1
new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
以及调用方法
1
Converter<ResponseBody, ResponseT> responseConverter = createResponseConverter(retrofit, method, responseType);
我们看
createResponseConverter
1
2
3
4
5
6
7
8
9private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter(
Retrofit retrofit, Method method, Type responseType) {
Annotation[] annotations = method.getAnnotations();
try {
return retrofit.responseBodyConverter(responseType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(method, e, "Unable to create converter for %s", responseType);
}
}
也就是这个 responseBodyConverter
实际来自 retrofit.responseBodyConverter
,也就是我们开发的时候写的那个 Converter
OK!完美了!基本就差不多了。
- Title: 阅读 Retrofit 源码
- Author: lucas
- Created at : 2025-04-02 20:17:50
- Updated at : 2025-04-23 20:35:49
- Link: https://darkflamemasterdev.github.io/2025/04/02/阅读-Retrofit-源码/
- License: This work is licensed under CC BY-NC-SA 4.0.