阅读 Retrofit 源码

阅读 Retrofit 源码

lucas Lv4

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public <T> T create(final Class<T> service) {
validateServiceInterface(service);
return (T)
Proxy.newProxyInstance(
service.getClassLoader(),
new Class<?>[] {service},
new InvocationHandler() {
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 (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
args = args != null ? args : emptyArgs;
Reflection reflection = Platform.reflection;
return reflection.isDefaultMethod(method)
? reflection.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(service, method).invoke(proxy, args);
}
});
}

总体他一共就两行代码,第一行是 this.validateServiceInterface(service);,第二行是 return Proxy.newProxyInstance(...) 下面的都是他的参数

validateServiceInterface(验证)

首先我们看 this.validateServiceInterface(service);

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
private void validateServiceInterface(Class<?> service) {
if (!service.isInterface()) {
throw new IllegalArgumentException("API declarations must be interfaces.");
}
Deque<Class<?>> check = new ArrayDeque<>(1);
check.add(service);
while (!check.isEmpty()) {
Class<?> candidate = check.removeFirst();
if (candidate.getTypeParameters().length != 0) {
StringBuilder message =
new StringBuilder("Type parameters are unsupported on ").append(candidate.getName());
if (candidate != service) {
message.append(" which is an interface of ").append(service.getName());
}
throw new IllegalArgumentException(message.toString());
}
Collections.addAll(check, candidate.getInterfaces());
}
if (validateEagerly) {
Reflection reflection = Platform.reflection;
for (Method method : service.getDeclaredMethods()) {
if (!reflection.isDefaultMethod(method)
&& !Modifier.isStatic(method.getModifiers())
&& !method.isSynthetic()) {
loadServiceMethod(service, method);
}
}
}
}
  • 一开始它进行了 service.isInterface() 的判断,这个 service 就是我们在调用 Retrofit.create() 传入的参数,也就是我们自己声明的接口,比如:

    1
    2
    3
    4
    interface GitHubService {
    @GET("users/{user}/repos")
    fun listRepos(@Path("user") user: String?): Call<List<Repo>>
    }
    • 为什么要判断这个是不是接口呢?因为 Retrofit 只允许你声明接口,这是它的设计意图,也是后面使用动态代理的条件
  • 后面它在确认你声明的是接口之后,生成了一个叫 checkDeque(双端队列),紧接着进行了一个 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
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
interface Image {
void display();
}

class RealImage implements Image {
private String fileName;

public RealImage(String fileName) {
this.fileName = fileName;
loadFromDisk(fileName);
}

@Override
public void display() {
System.out.println("Displaying " + fileName);
}

private void loadFromDisk(String fileName) {
System.out.println("Loading " + fileName);
}
}

class ImageInvocationHandler implements InvocationHandler {
private RealImage realImage;
private String fileName;

public ImageInvocationHandler(String fileName) {
this.fileName = fileName;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (realImage == null) {
realImage = new RealImage(fileName);
}
System.out.println("图片正在加载,请等待");
return method.invoke(realImage, args);
}
}

public class DynamicProxyImageDemo {
public static void main(String[] args) {
Image image = (Image) Proxy.newProxyInstance(
Image.class.getClassLoader(),
new Class<?>[]{Image.class},
new ImageInvocationHandler("wallpaper.png")
);

// 图像将从磁盘加载
image.display();

ProxyUtils.generateClassFile(RealImage.class, "ImageDynamicProxy");
}
}

输出结果:

1
2
3
Loading wallpaper.png
图片正在加载,请等待
Displaying wallpaper.png

你会发现,在 Main 函数里,你使用了 ProxyImage 但却最终实际上调用了 RealImagedisplay() ,这就是代理模式中的静态代理

那么动态代理呢?

动态代理

和静态代理类似,动态代理是在运行的时候,生成 ProxyImage 来代理 ReadImage 处理一些代码逻辑。

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
interface Image {
void display();
}

// 真实的 Image 类
class RealImage implements Image {
String fileName;

public RealImage(String fileName) {
this.fileName = fileName;
loadFromDisk(fileName);
}

@Override
public void display() {
System.out.println("Displaying " + fileName);
}

private void loadFromDisk(String fileName) {
System.out.println("Loading " + fileName);
}
}

// 方法调用类 InvocationHandler
class ImageInvocationHandler implements InvocationHandler {
private RealImage realImage;
private String fileName;

public ImageInvocationHandler(RealImage realImage, String fileName) {
this.realImage = realImage;
this.fileName = fileName;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (realImage == null) {
realImage = new RealImage(fileName);
}
System.out.println("图片正在加载,请等待");
return method.invoke(realImage, args);
}
}

// 调用代理类的地方
public class DynamicProxyImageDemo {
public static void main(String[] args) {
RealImage realImage = new RealImage("D:\\1.jpg");
Image image = (Image) Proxy.newProxyInstance(
Image.class.getClassLoader(),
new Class<?>[]{Image.class},
new ImageInvocationHandler(realImage,realImage.fileName)
);

// 图像将从磁盘加载
image.display();
}
}

同样,输出结果如下:

1
2
3
Loading wallpaper.png
图片正在加载,请等待
Displaying 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
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
import sun.misc.ProxyGenerator;
import java.io.FileOutputStream;
import java.io.IOException;

public class ProxyUtils {
/**
* 将根据类信息动态生成的二进制字节码保存到硬盘中,默认的是clazz目录下
* params: clazz 需要生成动态代理类的类
* proxyName: 为动态生成的代理类的名称
*/
public static void generateClassFile(Class clazz, String proxyName) {
// 根据类信息和提供的代理类名称,生成字节码
byte[] classFile = ProxyGenerator.generateProxyClass(proxyName, clazz.getInterfaces());
String paths = clazz.getResource(".").getPath();
System.out.println(paths);
FileOutputStream out = null;
try {
//保留到硬盘中
out = new FileOutputStream(paths + proxyName + ".class");
out.write(classFile);
out.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

这是用来生成动态代理生成类的工具类

关于贴源码的提示

我一直认为贴出 import 是很重要的,因为 java 里也很有很多重复的同名类名,贴出来 import 可以帮阅读者

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
public final class ImageDynamicProxy extends Proxy implements Image {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;

public ImageDynamicProxy(InvocationHandler var1) throws {
super(var1);
}

// super.h.invoke 就是使用 InvocationHandler.invoke()
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}

// super.h.invoke 就是使用 InvocationHandler.invoke()
public final void display() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}

// super.h.invoke 就是使用 InvocationHandler.invoke()
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}

// super.h.invoke 就是使用 InvocationHandler.invoke()
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}

static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("org.czb.dynamic_proxy.Image").getMethod("display");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(((Throwable)var2).getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(((Throwable)var3).getMessage());
}
}
}

可以看到,这个动态生成的类,继承了 Proxy 类,实现了 Image 接口,并且重写了接口的所有方法

在最下面有一个 static 代码块,在类加载时自动执行一次,初始化了里面的所有方法(equalsdisplaytoStringhashCode)的 Method 静态对象

在重写的每个接口的方法里,主要方法内容都是 super.h.invoke,也就是 InvocationHandler.invoke()

所以对于所有的方法都会调用 invoke,如果你要在遇到不同的方法时处理不同的逻辑,就在 invoke 的实现里可以使用 switch-case 对不同的方法进行不同的实现

这就是所有动态代理的内部原理

  • 代理模式的主要意义:
    1. 控制访问
      代理对象可以对客户端的请求进行拦截和控制。比如,可以在调用真实对象的方法之前进行权限校验、延迟加载、日志记 录或事务控制等操作,从而增加额外的安全性和灵活性。
    2. 解耦与增强扩展性
      通过引入代理层,可以将一些横切关注点(例如日志记录、缓存、远程通信等)从核心业务逻辑中分离出来,降低系统耦 合度,增强代码的可维护性和扩展性。
    3. 统一接口
      无论是直接访问真实对象,还是通过代理对象访问,都对客户端透明。客户端只需依赖接口,不必关心对象是代理还是具 体实现,简化了程序设计和后期维护。

继续看 Retrofit

newProxyInstance
  • newProxyInstance 中,声明了一个 emptyArgs 这个一看就是要在 argsnull 的时候,传入的方法参数(来自第 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
    34
    final class Platform {
    static final @Nullable 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 ReflectionJava8,我们一个个看

    • Android24

      1
      2
      3
      4
      5
      6
      7
      static final class Android24 extends Reflection {
      @Override
      boolean isDefaultMethod(Method method) {
      return method.isDefault();
      }
      ......
      }

      这个方法调用的是用于判断是不是接口声明时候的实现的 default 方法

    • Reflection

      1
      2
      3
      4
      5
      6
      class Reflection {
      boolean isDefaultMethod(Method method) {
      return false;
      }
      ......
      }

      这里直接返回了 false

    • Java8

      1
      2
      3
      4
      5
      6
      7
      8
      @IgnoreJRERequirement // Only used on JVM.
      static class Java8 extends Reflection {
      @Override
      boolean isDefaultMethod(Method method) {
      return method.isDefault();
      }
      ......
      }

      这里也是直接判断是不是接口实现的 default 方法

      method.isDefault()

      从 Java 8 开始,接口(interface)中可以包含带有实现的方法,这种方法通过关键字 default 声明。例如:

      1
      2
      3
      4
      5
      6
      @IgnoreJRERequirement // 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 实现
  • 我们继续看,当判断了接口里有默认实现,我们这里就直接调用 invokeDefaultMethod 方法,这个方法又是什么呢?
    我们还是看看实现,这次我们直接放结论,如果是 Reflection,就直接抛出 AssertionError因为他没法声明 default 方法,如果是 Java8 或者 Android24 就直接使用 DefaultMethodSupport.invoke 调用 default 方法,也就是说,Retrofit 会认为你自己实现好了方法调用逻辑而不会帮你生成内部实现。

  • 最后,如果你没有接口的 default 实现,那么就轮到 Retrofit 来帮你实现了,也就是最后的 loadServiceMethod

loadServiceMethod

我们看到最后一行,loadServiceMethod(service, method).invoke(proxy, args); 这里调用了两个方法,第一个 loadServiceMethod 返回一个 ServiceMethod,然后调用 ServiceMethodinvoke 方法,我直接进去看看源码

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
ServiceMethod<?> loadServiceMethod(Class<?> service, Method method) {
while (true) {
// Note: Once we are minSdk 24 this whole method can be replaced by computeIfAbsent.
Object lookup = serviceMethodCache.get(method);
if (lookup instanceof ServiceMethod<?>) {
// Happy path: method is already parsed into the model.
return (ServiceMethod<?>) lookup;
}
if (lookup == null) {
// Map does not contain any value. Try to put in a lock for this method. We MUST synchronize
// on the lock before it is visible to others via the map to signal we are doing the work.
Object lock = new Object();
synchronized (lock) {
lookup = serviceMethodCache.putIfAbsent(method, lock);
if (lookup == null) {
// On successful lock insertion, perform the work and update the map before releasing.
// Other threads may be waiting on lock now and will expect the parsed model.
ServiceMethod<Object> result;
try {
result = ServiceMethod.parseAnnotations(this, service, method);
} catch (Throwable e) {
// Remove the lock on failure. Any other locked threads will retry as a result.
serviceMethodCache.remove(method);
throw e;
}
serviceMethodCache.put(method, result);
return result;
}
}
}
// Either the initial lookup or the attempt to put our lock in the map has returned someone
// else's lock. This means they are doing the parsing, and will update the map before
// releasing
// the lock. Once we can take the lock, the map is guaranteed to contain the model or null.
// Note: There's a chance that our effort to put a lock into the map has actually returned a
// finished model instead of a lock. In that case this code will perform a pointless lock and
// redundant lookup in the map of the same instance. This is rare, and ultimately harmless.
synchronized (lookup) {
Object result = serviceMethodCache.get(method);
if (result == null) {
// The other thread failed its parsing. We will retry (and probably also fail).
continue;
}
return (ServiceMethod<?>) result;
}
}
}
  • 我们发现这个 loadServiceMethod 方法总体来说就是返回了一个 ServiceMethod,我们先看它怎么实现的,再看 invoke
  • 这个方法里是一整个 while 循环
  • 先是在 serviceMethodCache 里取出一个 Object
    • 如果这个 Object 的类型是 ServiceMethod,那就说明这个方法就已经被加载了,就会直接返回这个对象。
    • 如果它是空的,那就说明方法还没被加载,就会 new 一个 Object lock
      • 然后紧接着我们对这个 lock 加锁,调用 putIfAbsent 将这个 method 作为 key 放进去,valuelock,再次判断 lookup 为空(这里 putIfAbsent 放进去 method 之后,如果之前没有这个 key 就会返回 null,然后使用 if (lookup == null) 所以这里不仅进行了双重锁检验还将 method 放进去了,valuelock
      • 然后 result = ServiceMethod.parseAnnotations(this, service, method); 生成一个名为 resultServiceMethod 的对象,也就是初始化这个方法。
      • 如果这里 catch 到问题,会把刚才添加进去的 method移除掉
      • 如果初始化成功,就更新缓存,也就是将刚才初始化的 result 放进 serviceMethodCache 里面
寻找 invoke
  • 看明白可这个方法我们先回过头看看 invoke

    1
    abstract @Nullable T invoke(Object instance, Object[] args);

    发现他就是一个抽象方法,没有实现,那我们就得找找这个类的实现了,所以继续看 loadServiceMethod 返回的对象,也就是最后的那个 ServiceMethod.parseAnnotations

ServiceMethod.parseAnnotations

进入这个源码我们发现,他和 invoke 在一个类里实现,那我们看 ServiceMethod.parseAnnotations 它内部是怎么实现的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Class<?> service, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, service, 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);
}

这个方法很简单,我们一步步看

  • 一开始生成了一个 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
    30
    static boolean hasUnresolvableType(@Nullable 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
2
3
4
5
6
@Override
final @Nullable ReturnT invoke(Object instance, Object[] args) {
Call<ResponseT> call =
new OkHttpCall<>(requestFactory, instance, args, callFactory, responseConverter);
return adapt(call, args);
}
  • 这个方法是创建饿了一个 Call 而且还是一个 OkHttpCall 我们简单看一下,它实现了 Call 接口,如果你看过 OkHttp 的源码, 这里应该会感觉很熟悉,我们后面再分析,再继续看 invoke
  • 然后调用了 adapt 方法,那 adapt 方法又是怎么实现的,我们继续看
寻找 adapt
1
protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);

又是抽象方法,所以我们需要像找 invoke 一样找找这个 HttpServiceMethod 的具体实现了,回去继续看它的 HttpServiceMethod.parseAnnotations

HttpServiceMethod.parseAnnotations
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
boolean continuationWantsResponse = false;
boolean continuationBodyNullable = false;
boolean continuationIsUnit = false;

Annotation[] annotations = method.getAnnotations();
Type adapterType;
if (isKotlinSuspendFunction) {
Type[] parameterTypes = method.getGenericParameterTypes();
Type responseType =
Utils.getParameterLowerBound(
0, (ParameterizedType) parameterTypes[parameterTypes.length - 1]);
if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
// Unwrap the actual body type from Response<T>.
responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
continuationWantsResponse = true;
} else {
if (getRawType(responseType) == Call.class) {
throw methodError(
method,
"Suspend functions should not return Call, as they already execute asynchronously.\n"
+ "Change its return type to %s",
Utils.getParameterUpperBound(0, (ParameterizedType) responseType));
}

continuationIsUnit = Utils.isUnit(responseType);
// TODO figure out if type is nullable or not
// Metadata metadata = method.getDeclaringClass().getAnnotation(Metadata.class)
// Find the entry for method
// Determine if return type is nullable or not
}

adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
} else {
adapterType = method.getGenericReturnType();
}

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>)");
}
if (requestFactory.httpMethod.equals("HEAD")
&& !Void.class.equals(responseType)
&& !Utils.isUnit(responseType)) {
throw methodError(method, "HEAD method must use Void or Unit as response type.");
}

Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);

okhttp3.Call.Factory callFactory = retrofit.callFactory;
if (!isKotlinSuspendFunction) {
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
} else if (continuationWantsResponse) {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>)
new SuspendForResponse<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
} else {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>)
new SuspendForBody<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
continuationBodyNullable,
continuationIsUnit);
}
}

这个方法确实有点长,我们粗略看一下,我们直接找 return,也就是看看他到底是怎么返回一个 HttpServiceMethod

也就是最后一段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
if (!isKotlinSuspendFunction) {
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
} else if (continuationWantsResponse) {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>)
new SuspendForResponse<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
} else {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>)
new SuspendForBody<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
continuationBodyNullable,
continuationIsUnit);
}

也就是说,这里通过判断是否是 suspend 方法来生成对应的 HttpServiceMethod,既然是 suspend 方法,那肯定也得生成 suspend 方法啊,这是对于 kotlin 协程的适配

我们直接看对于普通方法的实现,这篇文章就先不管 suspend 方法,我们直接看 CallAdapted

找到 adapt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
private final CallAdapter<ResponseT, ReturnT> callAdapter;
CallAdapted(
RequestFactory requestFactory,
okhttp3.Call.Factory callFactory,
Converter<ResponseBody, ResponseT> responseConverter,
CallAdapter<ResponseT, ReturnT> callAdapter) {
super(requestFactory, callFactory, responseConverter);
this.callAdapter = callAdapter;
}
@Override
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return callAdapter.adapt(call);
}
}

这个 CallAdapted 实现了 HttpServiceMethod 并且实现了 adapt

注意

  • CallAdapted 的含义就是被适配的 Call ,很多英语层面的含义还是可以看出来一些代码的设计意图的

然后我们此时可以继续往源码内部深入,找到 retrofit.callAdapterRetrofit 类里面有一个 callAdapterFactories 而这个 callAdapterFactories 会在 Retrofit 的构造函数里初始化,然后我们想到 Retrofit 我们平时不都是 build 出来的吗?!就像这样

1
2
3
4
val retrofit = Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.build()

然后我们发现这文件里确实有 build 方法,这里一下子就串起来了。

我们继续深入挖掘,找找这个 callAdapterFactories 是这么初始化的,找到 DefaultCallAdapterFactory,并发现如下代码

1
2
3
4
5
6
7
8
9
10
11
return new CallAdapter<Object, Call<?>>() {
@Override
public Type responseType() {
return responseType;
}

@Override
public Call<Object> adapt(Call<Object> call) {
return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
}
};

然后大致就知道这个就是返回一个 Call 的实例(在这里是 ExecutorCallbackCall),返回看代码注释里写的就是

call-注释.png

闭环了

所以我们挖了这么久回头梳理一下,就是要搞明白 loadServiceMethod(service, method).invoke(proxy, args) 这行代码最终干了什么————就是返回了一个 ExecutorCallbackCall

  • loadServiceMethod 会返回一个 CallAdapted ,这个 CallAdapted 继承了 HttpServiceMethod
  • 返回他之后,会调用 invoke,这个 invoke 会调用 adapt,最终调用 AdapterFactoryget 返回一个 ExecutorCallbackCall
  • 总结就是动态代理的 InvocationHandlerinvoke 方法会返回一个 ExecutorCallbackCall,也就是我们写的 val service = retrofit.create(GitHubService::class.java)service 里面会调用 invoke 并返回一个 ExecutorCallbackCall
  • 我们看看 ExecutorCallbackCall 这个方法里面也有 enqueue 那么既然动态代理就是为了生成这个 ExecutorCallbackCall 是不是就意味着这个 enqueue 就是我们开发的时候写的那个 enqueue————还真是!!!!
  • 我们看看这个 enqueue 实现了什么吧
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
34
public Call<Object> adapt(Call<Object> call) {
return (Call<Object>)(executor == null ? call : new ExecutorCallbackCall(executor, call));
}
// ...代码隔离...

ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}

@Override
public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
delegate.enqueue(
new Callback<T>() {
@Override
public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(
() -> {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on
// cancellation.
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
});
}
@Override
public void onFailure(Call<T> call, final Throwable t) {
callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
}
});
}
  • 这个 delegate 就是我们一开始调用 adapt 填入的那个 Call,也就是 OkHttpCall,一会儿我们再看 OkHttpCall 我们先把这个看完
  • 也就是说这个 ExecutorCallbackCall 把这个 OkHttpCall 包了一层
  • 这个 ExecutorCallbackCallenqueue 里面使用了一个 Executor 切了线程,并调用了 callbackonFailureonResponse(也就是开发时候写的 callback
  • 这里切线程是有点奇怪的,因为如果最终使用的是 OkHttpenqueue,那就没有必要在这里切线程了,所以我们再深挖一下,看看这个 callbackExecutor 里面是怎么操作的
  • 我们找到这个 callbackExecutor 是在 Retrofit 的构造方法里初始化的 callbackExecutor = Platform.callbackExecutor; 点进去发现是这样的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
static {
switch (System.getProperty("java.vm.name")) {
case "Dalvik":
callbackExecutor = new AndroidMainExecutor();
if (VERSION.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();
}
}
  • 又是熟悉的代码,我们看看这个 AndroidMainExecutor 的实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    final 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

注意

这个 OkHttpCallCall 都是 Retrofit 里面的,并非 OkHttp 里面的

我们挑一个关键函数看,比如经常使用的 enqueue

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
okhttp3.Call call;
Throwable failure;
synchronized(this) {
if (this.executed) {
throw new IllegalStateException("Already executed.");
}
this.executed = true;
call = this.rawCall;
failure = this.creationFailure;
if (call == null && failure == null) {
try {
call = this.rawCall = this.createRawCall();
} catch (Throwable t) {
Utils.throwIfFatal(t);
failure = this.creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
} else {
if (this.canceled) {
call.cancel();
}
call.enqueue(new okhttp3.Callback() {
public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
response = OkHttpCall.this.parseResponse(rawResponse);
} catch (Throwable e) {
Utils.throwIfFatal(e);
this.callFailure(e);
return;
}
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
Utils.throwIfFatal(t);
t.printStackTrace();
}
}
public void onFailure(okhttp3.Call call, IOException e) {
this.callFailure(e);
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
Utils.throwIfFatal(t);
t.printStackTrace();
}

}
});
}
}
  • 代码有点长,但其实并不复杂,做了一些判断,然后调用 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
    31
    Response<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
    9
    private 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.
Comments