Retrofit 原理与实战:动态代理、类型安全与协程集成的优雅设计

25 阅读5分钟

Android 网络深度系列 · 第 4 篇

系列导航:第1篇:HTTP协议全解 | 第2篇:HTTPS与网络安全 | 第3篇:OkHttp架构剖析 | 第4篇:Retrofit原理与实战 | 第5篇:WebSocket与长连接 | 第6篇:网络实战场景


前言

上一篇我们拆了 OkHttp 的骨架——拦截器链、连接池、缓存策略,明白了它是怎么"做"网络请求的。

这篇讲 Retrofit,它是怎么让网络请求变得"优雅"的。

Retrofit 是 Square 的另一个杰作。如果你是 Android 开发者,大概率每天都在用。但你有没有想过——为什么写个接口、加个注解,就能发起 HTTP 请求?那个接口明明没有实现类,调用时是怎么执行的?

答案藏在 动态代理 里。

⚠️ 本文基于 Retrofit 2.9.0 / 2.11.0 源码分析,所有示例使用 Kotlin。Retrofit 2.11 是当前最新稳定版,与 2.9.x 差异不大,但修复了一些协程相关的 bug。


1. Retrofit 的设计哲学

在动源码之前,先理解 Retrofit 的设计思路——搞懂了哲学,读代码才不迷路。

1.1 声明式 vs 命令式

这是 Retrofit 最核心的思想转变。

命令式:告诉机器每一步怎么做。

// 命令式——你要描述怎么构建请求、怎么执行
val request = Request.Builder()
    .url("https://api.example.com/users/1")
    .get()
    .build()
​
val call = okHttpClient.newCall(request)
val response = call.execute()
val body = response.body?.string()
// 然后还要自己解析 JSON...

声明式:告诉机器你要什么,由框架解决怎么做的细节。

// 声明式——只描述你要什么
interface ApiService {
    @GET("users/{id}")
    suspend fun getUser(@Path("id") id: Int): User
}
​
// 调用方:拿到就是解析好的对象
val user = api.getUser(1)

差别在哪?命令式把做什么怎么做混在一起;声明式分离了意图和实现。

Retrofit 让你只声明"我要什么数据、从哪拿、怎么传参",底层的 URL 拼接、Header 注入、JSON 解析、线程调度全部封装掉。

这不仅是语法糖——它意味着你的网络层代码能够被静态分析、被 lint 检查、被编译期验证。你在 IDE 里写下 api.getUser("abc") 而接口声明的是 Int 时,编译器当场就报错。这在运行时拼 URL 的世界里是不可能的事。

1.2 关注点分离

Retrofit 把网络请求的职责拆成了三层:

职责具体实现
接口声明层定义 API 契约interface ApiService + 注解
适配层把 Call 转成目标类型CallAdapter
数据转换层JSON ↔ 对象Converter

这三层各管各的,通过 Retrofit.Builder 装配。

Retrofit.Builder()
    .baseUrl("https://api.example.com/")
    .client(okHttpClient)                        // 网络执行层(OkHttp)
    .addCallAdapterFactory(CoroutineCallAdapterFactory()) // 适配层
    .addConverterFactory(GsonConverterFactory.create())    // 数据转换层
    .build()

后面每一节都会深入这些组件的源码。

1.3 适配器模式贯穿始终

Retrofit 整个架构就是一套适配器模式的集大成者:

  • CallAdapter:把 Call<R> 适配成用户想要的东西(Observable<R>Flow<R>、直接返回值)
  • Converter:把 ResponseBody 适配成 User,把 User 适配成 RequestBody
  • 动态代理:本质也是一个适配器——把方法调用适配成 OkHttp Request

三个适配器层层嵌套:调用接口 → 动态代理 → OkHttp Request → CallAdapter → Converter

这种设计让 Retrofit 成为了 Android 生态中最可扩展的网络框架。想支持 Protobuf?加个 Converter。想返回 Flow?加个 CallAdapter。底层执行引擎想从 OkHttp 换成别的?也不是不行(虽然没人这么干)。


2. 动态代理核心

这是 Retrofit 最骚的部分。也是面试必考。

2.1 Java 动态代理原理

我们知道 Java 的 interface 没有实现类,无法直接 new。但动态代理可以在运行时凭空造出一个实现类,并把所有方法调用重定向到一个 InvocationHandler

先看一个最简单的例子:

// 1. 定义接口
interface HelloService {
    fun sayHello(name: String): String
}
​
// 2. InvocationHandler——所有方法调用的"入口"
val handler = InvocationHandler { proxy, method, args ->
    println("方法被调用了:${method.name}")
    
    when (method.name) {
        "sayHello" -> "Hello, ${args?.get(0)}!"
        "toString" -> "我是代理对象"
        "hashCode" -> 42
        else -> throw UnsupportedOperationException(method.name)
    }
}
​
// 3. 创建代理
val proxy = Proxy.newProxyInstance(
    HelloService::class.java.classLoader,     // 类加载器
    arrayOf(HelloService::class.java),         // 要代理的接口
    handler                                    // 方法拦截器
) as HelloService
​
// 4. 使用
println(proxy.sayHello("千珏"))  // → "Hello, 千珏!"

Proxy.newProxyInstance 干了两件事:

  1. 生成字节码:根据传入的接口,动态生成一个 $Proxy0 类,它继承了 Proxy 并实现了所有接口
  2. 创建实例:new 一个 $Proxy0 实例,传入 InvocationHandler

生成的 $Proxy0.sayHello() 的实现大概长这样:

// 这是 JVM 动态生成的字节码的反编译结果
public final class $Proxy0 extends Proxy implements HelloService {
    private static Method m1 = HelloService.class.getMethod("sayHello", String.class);
    private static Method m0 = Object.class.getMethod("hashCode");
    // ...更多 Method 对象
    
    public String sayHello(String name) {
        // 所有方法调用全部委托给 InvocationHandler
        return (String) super.h.invoke(this, m1, new Object[]{name});
    }
}

关键点:每一个接口方法对应的 Method 对象在静态初始化时就获取好了。这意味着 method.invoke() 的反射调用只发生一次(在 $Proxy0 的静态初始化块里),后续调用直接调用 InvocationHandler.invoke(),不需要再反射。

这也是 Retrofit 不需要 APT 就能高效工作的原因之一——代理对象的方法路由是纯虚方法分派,不是反射调用。

2.2 Retrofit.create() 源码拆解

有了上面的基础,看 Retrofit.create() 就简单了:

// Retrofit.java (简化)
public <T> T create(final Class<T> service) {
    // 校验:必须是接口、不能扩展其他接口、不能是泛型参数
    validateServiceInterface(service);
    
    return (T) Proxy.newProxyInstance(
        service.getClassLoader(),
        new Class<?>[]{service},
        new InvocationHandler() {
            private final Platform platform = Platform.get();
            
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // ★ 特殊处理 Object 方法
                if (method.getDeclaringClass() == Object.class) {
                    return method.invoke(this, args);
                }
                
                // ★ 特殊处理默认方法和 Kotlin 桥接方法
                if (platform.isDefaultMethod(method)) {
                    return platform.invokeDefaultMethod(method, service, proxy, args);
                }
                
                // ★ 核心逻辑:加载 ServiceMethod 并执行
                return loadServiceMethod(method).invoke(args);
            }
        }
    );
}

这个 InvocationHandler 做了三件事:

  1. Object 方法直通equals()hashCode()toString() 这些走默认实现,不进入 Retrofit 逻辑
  2. 默认方法处理:Java 8 接口默认方法和 Kotlin 桥接方法用 MethodHandle 直接调用
  3. 核心路径:调用 loadServiceMethod(method).invoke(args)——解析方法、构造请求、执行

2.3 为什么用动态代理而不是 APT

这是一个面试高频问题。

APT(Annotation Processing Tool) :编译时扫描注解,生成 Java 代码。其他框架(如 Dagger、Room、Glide)都用 APT。

那 Retrofit 为啥不用?

维度动态代理APT
编译依赖需要 annotationProcessor 配置
接口数量多数 App 只有 1-5 个接口不限
性能每个方法调用拦截一次 InvocationHandler直接调用生成代码,无拦截
灵活性同一接口可绑定不同 Retrofit 实例编译时确定,不灵活
字节码体积无生成文件每个接口生成一个实现类

Retrofit 选择动态代理的原因很务实:

  1. 不增加编译步骤:引入依赖就完事,加 APT 要多配置
  2. 接口数量少:一个 App 的 API 接口通常不超过 5 个,反射开销可忽略
  3. 运行时灵活性:同一接口的不同实例可以连不同的 baseUrl,APT 做不到
  4. 框架简洁:不需要单独维护代码生成器

当然,也有追求极致零反射的方案——Square 的实验分支 retrofit-kotlin-compiler 就是 APT 方案(KSP),但一直没有合并到主分支。社区评价是"锦上添花,不是刚需"。

2.4 ServiceMethod 缓存

create() 里调用了 loadServiceMethod(method)

// Retrofit.java
private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
​
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);
        }
    }
    return result;
}

关键设计:

  • ConcurrentHashMap + synchronized 双重检查:高并发下只解析一次
  • Method 对象作为 key:Method 的 identity 由声明类+方法名+参数类型唯一定义,天然不可变
  • 解析是懒加载的:只有第一次调用时才解析,不浪费启动时间

对比用 APT 的框架(如 Room),Retrofit 的 ServiceMethod 相当于在运行时做了 APT 的事——解析注解、构建请求模板。只不过它只解析一次,缓存起来,后续调用只走 invoke()

2.5 面试:调用接口方法时的完整调用链

api.getUser(1)
  │
  ├─ 1. 动态代理捕获方法调用
  │    Proxy.getUser() → InvocationHandler.invoke(proxy, method, args)
  │
  ├─ 2. 加载 ServiceMethod(从缓存或新建)
  │    loadServiceMethod(method) → ServiceMethod.parseAnnotations()
  │      ├─ 解析方法注解(@GET@POST、Headers)
  │      ├─ 解析参数注解(@Path@Query@Body)
  │      ├─ 选择 CallAdapter(返回类型适配器)
  │      └─ 选择 Converter(请求/响应数据转换器)
  │
  ├─ 3. 创建 OkHttpCall
  │    ServiceMethod.invoke(args) → 创建 OkHttpCall(持有 RequestFactory)
  │      └─ 如果是 suspend 函数,创建 SuspendForBody / SuspendForResponse
  │
  ├─ 4. 发起请求
  │    OkHttpCall.enqueue() / execute() → OkHttpClient.newCall(request)
  │      └─ 经过 OkHttp 拦截器链 → 实际网络 I/O
  │
  └─ 5. 结果转换
       OkHttp 响应 → Converter<ResponseBody, T>.convert()
       → 返回 User 对象 / 协程恢复

整条链路由三个核心对象串联起来:

  • ServiceMethod:元数据的化身,知道接口怎么调用、参数怎么传、结果怎么转。相当于接口的"反射描述"。
  • OkHttpCall:真正的网络执行者,把 ServiceMethod 的元数据变成真正的 OkHttp 请求。它是 Call<T> 的实现类。
  • CallAdapter:把 OkHttpCall<T>(原始 Call)包装成用户想要的形式(suspend、Flow、RxJava)。

3. 注解解析

这节深入 ServiceMethod.parseAnnotations() 内部,看注解是怎么变成 OkHttp Request 的。

3.1 ServiceMethod.parseAnnotations()

// ServiceMethod.java (简化)
abstract class ServiceMethod<T> {
    
    static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
        // 1. 解析方法级别的信息(@GET/POST、URL、Headers)
        RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
        
        // 2. 获取方法的返回类型
        Type returnType = method.getGenericReturnType();
        
        // 3. 处理 Kotlin suspend 函数
        //    如果最后一个参数是 Continuation,提取实际返回类型
        if (Utils.hasUnresolvableType(returnType)) {
            throw new IllegalArgumentException("...");
        }
        
        // 4. 找到合适的 CallAdapter
        CallAdapter<T, ?> callAdapter = createCallAdapter(retrofit, method, returnType);
        
        // 5. 找到合适的 Converter
        Converter<ResponseBody, T> responseConverter = createResponseConverter(retrofit, method, returnType);
        
        return new HttpServiceMethod<>(requestFactory, callAdapter, responseConverter);
    }
}

解析分为两阶段:

阶段一RequestFactory.parseAnnotations()——解析注解,产生一个"请求模板"。 阶段二:构建 CallAdapter 和 Converter——确定怎么执行和怎么转换。

3.2 RequestFactory——注解到请求模板

RequestFactory 是 Retrofit 把接口注解翻译成 OkHttp Request 的关键。

// RequestFactory.java (简化)
final class RequestFactory {
    
    private final String httpMethod;       // GET / POST / PUT / DELETE 等
    private final String relativeUrl;      // 相对路径,如 "users/{id}"
    private final Headers headers;         // 固定头部
    private final MediaType contentType;   // Content-Type
    private final boolean hasBody;         // 是否带请求体(POST/PUT)
    
    private final ParameterHandler<?>[] parameterHandlers;  // 参数处理器数组
    
    // ★ 核心方法:构建 OkHttp Request
    okhttp3.Request create(Object[] args) {
        // 使用 RequestBuilder 构建器模式
        RequestBuilder requestBuilder = new RequestBuilder(...);
        
        // 遍历参数处理器,逐个添加参数
        // parametersHandlers 在解析注解时就已经确定了
        for (int i = 0; i < argumentCount; i++) {
            parameterHandlers[i].apply(requestBuilder, args[i]);
        }
        
        return requestBuilder.build();
    }
}

关键设计:RequestFactory 把"参数处理逻辑"抽象成了 ParameterHandler 对象数组。

每一个方法参数(比如 @Path("id") Int id)在解析时都被转换成了一个 ParameterHandler 实例。执行时只需要遍历数组执行 apply(),不需要再次解析注解。

3.3 方法注解解析

RequestFactory.parseAnnotations() 内部对 method 做了一轮反射遍历:

// RequestFactory.Builder.parseMethodAnnotations() (简化)
for (Annotation annotation : method.getAnnotations()) {
    if (annotation instanceof GET) {
        parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
    } else if (annotation instanceof POST) {
        parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
    } else if (annotation instanceof PUT) {
        parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
    } else if (annotation instanceof DELETE) {
        parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
    } else if (annotation instanceof HEAD) {
        parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
    } else if (annotation instanceof PATCH) {
        parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
    } else if (annotation instanceof OPTIONS) {
        parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
    } else if (annotation instanceof HTTP) {
        parseHttpMethodAndPath(((HTTP) annotation).method(), ((HTTP) annotation).path(), ((HTTP) annotation).hasBody());
    } else if (annotation instanceof Headers) {
        parseHeaders(((Headers) annotation).value());  // 解析静态头部
    } else if (annotation instanceof Multipart) {
        isMultipart = true;
    } else if (annotation instanceof FormUrlEncoded) {
        isFormEncoded = true;
    }
}

parseHttpMethodAndPath() 把 URL 模板中的路径参数({id})解析出来,但不是直接替换——它记录下占位符的位置和名称,在执行时才替换。

// parseHttpMethodAndPath 的核心逻辑
private void parseHttpMethodAndPath(String method, String path, boolean hasBody) {
    this.httpMethod = method;
    this.hasBody = hasBody;
    this.relativeUrl = path;
    
    // 解析 {param} 占位符
    // 例如 "users/{id}/posts/{postId}" → 两个路径参数
    Pattern PARAM_URL_REGEX = Pattern.compile("\{([a-zA-Z][a-zA-Z0-9_-]*)\}");
    Matcher matcher = PARAM_URL_REGEX.matcher(path);
    while (matcher.find()) {
        String name = matcher.group(1);
        // 检查是否已经有过这个参数名
        if (gotPlaceholder(name)) {
            throw methodError("URL "%s" has duplicate path parameter: %s", path, name);
        }
        gotPathParam(name);
    }
    
    // 验证路径不以 / 开头(由 baseUrl 处理)
    // 验证路径参数数量一致
}

3.4 参数注解解析

每个方法参数可以有 0-2 个注解,RequestFactory.Builder 在 build() 时遍历参数:

// RequestFactory.Builder (简化)
for (int i = 0; i < method.getParameterTypes().length; i++) {
    ParameterHandler<?> handler = null;
    
    for (Annotation annotation : method.getParameterAnnotations()[i]) {
        handler = parseParameter(handler, annotation, i);
    }
    
    if (handler == null) {
        throw methodError("No Retrofit annotation found. (parameter #%d)", i);
    }
    
    parameterHandlers[i] = handler;
}

每个注解类型对应一个 ParameterHandler 子类:

// ParameterHandler 的子类体系
abstract class ParameterHandler<T> {
    abstract void apply(RequestBuilder builder, T value) throws IOException;
    
    // @Path
    static final class Path<T> extends ParameterHandler<T> {
        private final String name;
        private final Converter<T, String> valueConverter;
        
        void apply(RequestBuilder builder, T value) {
            builder.addPathParam(name, valueConverter.convert(value));
        }
    }
    
    // @Query
    static final class Query<T> extends ParameterHandler<T> {
        private final String name;
        private final Converter<T, String> valueConverter;
        private final boolean encoded;
        
        void apply(RequestBuilder builder, T value) {
            if (value != null) {
                builder.addQueryParam(name, valueConverter.convert(value), encoded);
            }
        }
    }
    
    // @Body — 完全不同的逻辑
    static final class Body<T> extends ParameterHandler<T> {
        private final Converter<T, RequestBody> converter;
        
        void apply(RequestBuilder builder, T value) {
            if (value == null) {
                throw new IllegalArgumentException("Body parameter value must not be null.");
            }
            builder.setBody(converter.convert(value));
        }
    }
    
    // @Header
    static final class Header<T> extends ParameterHandler<T> {
        private final String name;
        private final Converter<T, String> valueConverter;
        
        void apply(RequestBuilder builder, T value) {
            if (value != null) {
                builder.addHeader(name, valueConverter.convert(value));
            }
        }
    }
    
    // @Field (用于 FormUrlEncoded)
    static final class Field<T> extends ParameterHandler<T> {
        private final String name;
        private final Converter<T, String> valueConverter;
        private final boolean encoded;
        
        void apply(RequestBuilder builder, T value) {
            if (value != null) {
                builder.addFormField(name, valueConverter.convert(value), encoded);
            }
        }
    }
    
    // @Part (用于 Multipart)
    static final class Part<T> extends ParameterHandler<T> {
        private final Headers headers;
        private final Converter<T, RequestBody> converter;
        
        void apply(RequestBuilder builder, T value) {
            builder.addPart(headers, converter.convert(value));
        }
    }
}

可以看到 ParameterHandler 的职责极其单一:把一个参数值应用(apply)到 RequestBuilder 上。它不需要知道参数的来源,也不关心其他参数。

3.5 完整请求构建流程

当调用 api.getUser(1) 时,RequestFactory.create(args) 内部:

// RequestBuilder(内部类,构建 OkHttp Request)
final class RequestBuilder {
    
    okhttp3.Request build() {
        // 1. 拼接完整 URL
        HttpUrl url = baseUrl.resolve(relativeUrl);
        // 如果 URL 包含路径参数占位符 {id},
        // 在 addPathParam() 时已经完成了替换
        
        // 2. 设置方法 + 添加查询参数
        // 这些是由 ParameterHandler.Query.apply() 添加的
        
        // 3. 构建 Request
        Request.Builder requestBuilder = new Request.Builder();
        requestBuilder.url(url);
        requestBuilder.method(httpMethod, body);
        
        // 4. 添加 Header(来自 @Headers 和 @Header 参数)
        for (Header header : headers) {
            requestBuilder.addHeader(header.name, header.value);
        }
        
        return requestBuilder.build();
    }
}

生成的一个实际的 OkHttp Request 大概长这样:

GET https://api.example.com/users/1?include_details=true HTTP/1.1
Authorization: Bearer xxxxx
Content-Type: application/json

整个过程没有反射调用——RequestFactory 在第一次调用时把所有注解解析成 ParameterHandler 数组,后续调用只是遍历数组执行 apply()。这是 Retrofit 高性能的秘密之一:运行时唯一的反射发生在 Method 获取和 InvocationHandler 调用上,而这两个在第一次调用后就缓存好了


4. CallAdapter 机制

如果说动态代理和注解解析是 Retrofit 的骨架,那 CallAdapter 和 Converter 就是它的肌肉——决定了"怎么执行"和"怎么转换"。

4.1 CallAdapter 接口和作用

// CallAdapter.java
public interface CallAdapter<R, T> {
    // 返回实际类型的 Type(用于 Converter 匹配)
    Type responseType();
    
    // ★ 核心方法:把 Call<R> 适配成 T
    T adapt(Call<R> call);
    
    // 工厂——Retrofit 通过工厂链匹配 CallAdapter
    abstract class Factory {
        // 根据返回类型和注解,返回匹配的 CallAdapter,或 null
        public abstract @Nullable CallAdapter<?, ?> get(
            Type returnType, Annotation[] annotations, Retrofit retrofit
        );
        
        // 工具方法:获取参数类型(如 Flow<User> → User)
        protected static Type getParameterUpperBound(int index, ParameterizedType type) { ... }
        protected static Class<?> getRawType(Type type) { ... }
    }
}

responseType() 返回的是数据层的类型,不是用户层的类型。

举例来说:

方法签名用户层返回类型responseType
Call<User> getUser()Call<User>User
Observable<User> getUser()Observable<User>User
Flow<User> getUser()Flow<User>User
User getUser()UserUser

responseType 是 Converter 需要的——它要知道怎么反序列化响应体。CallAdapter 不关心这一点,它只知道要把 Call<R> 包装成什么类型。

4.2 Retrofit 如何选择 CallAdapter

// Retrofit.java (简化)
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
}
​
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast,
    Type returnType, Annotation[] annotations) {
    
    // 遍历 callAdapterFactories 列表
    int start = callAdapterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
        CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
        if (adapter != null) {
            return adapter;
        }
    }
    
    throw new IllegalArgumentException("... 没有匹配的 CallAdapter");
}

createCallAdapter() 返回类型后,框架会用这个 responseType 去找匹配的 Converter<ResponseBody, R>

4.3 DefaultCallAdapterFactory——Android 平台的关键

DefaultCallAdapterFactory 是 Retrofit 默认的 CallAdapter 工厂,负责处理返回类型为 Call<T> 的情况。但 Android 平台上其实不是它——是 Platform 里的内部实现。

// Platform.java——根据平台自动注入默认 CallAdapter
class Platform {
    
    static Platform get() {
        return PLATFORM;  // 自动检测:Android、Java 8 或 Java 9+
    }
    
    // Android 平台的 CallAdapter
    static final class Android extends Platform {
        
        @Override
        List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
            @Nullable Executor callbackExecutor) {
            
            // Android 平台的默认 CallAdapter
            DefaultCallAdapterFactory executorFactory = 
                new DefaultCallAdapterFactory(callbackExecutor);
            
            return Collections.singletonList(executorFactory);
        }
        
        @Override
        Executor defaultCallbackExecutor() {
            // ★ Android 特有的主线程调度
            // 通过 Handler 把回调投递到主线程 Looper
            return new Executor() {
                private final Handler handler = new Handler(Looper.getMainLooper());
                
                @Override
                public void execute(Runnable command) {
                    handler.post(command);
                }
            };
        }
    }
}

DefaultCallAdapterFactory 的实现:

// DefaultCallAdapterFactory.java
final class DefaultCallAdapterFactory extends CallAdapter.Factory {
    private final @Nullable Executor callbackExecutor;
    
    @Override
    public @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
        // 只处理 Call<T> 类型
        if (getRawType(returnType) != Call.class) {
            return null;
        }
        
        // 提取 Call<T> 中的 T
        final Type responseType = Utils.getCallResponseType(returnType);
        
        return new CallAdapter<Object, Call<?>>() {
            @Override
            public Type responseType() {
                return responseType;
            }
            
            @Override
            public Call<Object> adapt(Call<Object> call) {
                // ★ 把原始 Call 包装成 ExecutorCallbackCall
                // ExecutorCallbackCall 保证 enqueue 的回调在主线程执行
                if (callbackExecutor != null) {
                    return new ExecutorCallbackCall<>(callbackExecutor, call);
                }
                return call;
            }
        };
    }
}

ExecutorCallbackCall 是关键——它把 enqueue() 的回调通过 Handler 投递到主线程,这就是为什么 Android 上 Retrofit 的回调默认在主线程执行。

// ExecutorCallbackCall.java (简化)
static final class ExecutorCallbackCall<T> implements Call<T> {
    final Executor callbackExecutor;
    final Call<T> delegate;  // 真正的 OkHttpCall
    
    @Override
    public void enqueue(final Callback<T> callback) {
        delegate.enqueue(new Callback<T>() {
            @Override
            public void onResponse(Call<T> call, Response<T> response) {
                // 通过 callbackExecutor(主线程 Handler)执行回调
                callbackExecutor.execute(() -> {
                    if (delegate.isCanceled()) {
                        callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
                    } else {
                        callback.onResponse(ExecutorCallbackCall.this, response);
                    }
                });
            }
            
            @Override
            public void onFailure(Call<T> call, Throwable t) {
                callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
            }
        });
    }
    
    @Override
    public Response<T> execute() throws IOException {
        // execute 不涉及回调,不包装
        return delegate.execute();
    }
}

4.4 协程 suspend 适配(HttpServiceMethod)

当方法返回类型是 suspend 函数时,标准的 CallAdapter 工厂匹配不到,因为返回类型不是 Call<T> 而是 Object(suspend 函数编译后返回 Object,最后一个参数是 Continuation)。

这是 Retrofit 对 suspend 函数的特殊处理——不在 CallAdapter 层面,而在 HttpServiceMethod 层面。

// HttpServiceMethod.java (简化)
abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
    
    @Override
    ReturnT invoke(Object[] args) {
        // 构建 OkHttpCall
        OkHttpCall<ResponseT> call = new OkHttpCall<>(requestFactory, responseConverter);
        
        // 调用子类的 adapt() 方法
        return adapt(call, args);
    }
    
    // 抽象方法:由子类实现不同的适配逻辑
    protected abstract ReturnT adapt(OkHttpCall<ResponseT> call, Object[] args);
}

当方法返回类型检测到 Continuation 参数时,Retrofit 创建的不是普通的 CallAdapted 子类,而是 SuspendForBodySuspendForResponse

// HttpServiceMethod.java 内部的工厂方法
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> create(
    Retrofit retrofit, Method method, RequestFactory requestFactory) {
    
    // 判断是否是 suspend 函数
    boolean continuation = false;
    Type[] parameterTypes = method.getGenericParameterTypes();
    Class<?>[] parameterAnnotationsArray = ...;
    
    // 检查最后一个参数是否是 Continuation
    int parameterCount = parameterTypes.length;
    if (parameterCount > 0) {
        Type lastParamType = parameterTypes[parameterCount - 1];
        if (lastParamType instanceof ParameterizedType 
            && ((ParameterizedType) lastParamType).getRawType() == Continuation.class) {
            continuation = true;
        }
    }
    
    if (continuation) {
        // 如果方法声明了一个 Kotlin 的 suspend 函数
        // 且最后一个参数是 Continuation 类型
        
        // 判断是否需要 awaitResponse(返回 Response<T> 而不是 T)
        boolean isResponse = getRawType(returnType) == Response.class;
        
        if (isResponse) {
            return new SuspendForResponse<>(...);
        } else {
            return new SuspendForBody<>(...);
        }
    }
    
    // 非 suspend 函数走正常的 CallAdapter
    CallAdapter<ResponseT, ReturnT> callAdapter = ...;
    return new CallAdapted<>(..., callAdapter);
}

SuspendForBody——最常用的实现

// HttpServiceMethod.java 内部
static final class SuspendForBody<ResponseT> extends HttpServiceMethod<ResponseT, Object> {
    private final Converter<ResponseBody, ResponseT> responseConverter;
    
    @Override
    protected Object adapt(OkHttpCall<ResponseT> call, Object[] args) {
        // 取出 Continuation(Call<ResponseT> 中的最后一个参数)
        Continuation<ResponseT> continuation = (Continuation<ResponseT>) args[args.length - 1];
        
        // ★ 核心:使用 suspendCancellableCoroutine 桥接回调
        return KotlinExtensions.awaitBody(call, continuation);
    }
}
​
// KotlinExtensions.kt
suspend fun <T> Call<T>.await(): T {
    return suspendCancellableCoroutine { continuation ->
        enqueue(object : Callback<T> {
            override fun onResponse(call: Call<T>, response: Response<T>) {
                if (response.isSuccessful) {
                    val body = response.body()
                    if (body == null) {
                        // 返回 null 的情况(如 204 No Content)
                        continuation.resume(body)
                    } else {
                        continuation.resume(body)
                    }
                } else {
                    // HTTP 错误(4xx, 5xx)
                    continuation.resumeWithException(HttpException(response))
                }
            }
            
            override fun onFailure(call: Call<T>, t: Throwable) {
                // 网络错误(IO异常、超时等)
                continuation.resumeWithException(t)
            }
        })
        
        // 协程取消时取消请求
        continuation.invokeOnCancellation {
            call.cancel()
        }
    }
}

KotlinExtensions源码

Retrofit 还提供了两个 Kotlin 扩展,更好地解释了 await() vs awaitResponse()

// KotlinExtensions.kt
// 直接返回反序列化后的 body
suspend fun <T> Call<T>.await(): T {
    return awaitResponse().body()!!
}
​
// 返回包含状态码的 Reponse<T>
suspend fun <T> Call<T>.awaitResponse(): Response<T> {
    return suspendCancellableCoroutine { continuation ->
        enqueue(object : Callback<T> {
            override fun onResponse(call: Call<T>, response: Response<T>) {
                continuation.resume(response)
            }
            
            override fun onFailure(call: Call<T>, t: Throwable) {
                continuation.resumeWithException(t)
            }
        })
        
        continuation.invokeOnCancellation {
            call.cancel()
        }
    }
}

区别:

方法返回HTTP 错误网络错误空 body
await() / awaitBody()THttpException抛异常返回 null(204)
awaitResponse()Response<T>正常返回,不抛抛异常正常返回

4.4 自定义 CallAdapter 实战

Call<T> 包装为 Call<ApiResult<T>>,统一处理错误:

sealed class ApiResult<out T> {
    data class Success<T>(val data: T) : ApiResult<T>()
    data class HttpError(val code: Int, val message: String) : ApiResult<Nothing>()
    data class NetworkError(val exception: IOException) : ApiResult<Nothing>()
}

class ApiResultCall<T>(private val delegate: Call<T>) : Call<ApiResult<T>> {
    override fun enqueue(callback: Callback<ApiResult<T>>) {
        delegate.enqueue(object : Callback<T> {
            override fun onResponse(call: Call<T>, response: Response<T>) {
                val result = if (response.isSuccessful) {
                    val body = response.body()
                    if (body != null) ApiResult.Success(body)
                    else ApiResult.HttpError(response.code(), "Empty body")
                } else {
                    ApiResult.HttpError(response.code(), response.message())
                }
                callback.onResponse(this@ApiResultCall, Response.success(result))
            }
            override fun onFailure(call: Call<T>, t: Throwable) {
                val result = if (t is IOException) {
                    ApiResult.NetworkError(t)
                } else {
                    ApiResult.NetworkError(IOException(t))
                }
                callback.onResponse(this@ApiResultCall, Response.success(result))
            }
        })
    }
    override fun clone() = ApiResultCall(delegate.clone())
    override fun execute(): Response<ApiResult<T>> = throw UnsupportedOperationException()
    override fun isExecuted() = delegate.isExecuted
    override fun cancel() = delegate.cancel()
    override fun isCanceled() = delegate.isCanceled
    override fun request() = delegate.request()
    override fun timeout() = delegate.timeout()
}

class ApiResultCallAdapterFactory : CallAdapter.Factory() {
    override fun get(returnType: Type, annotations: Array<Annotation>, retrofit: Retrofit): CallAdapter<*, *>? {
        if (getRawType(returnType) != Call::class.java) return null
        val responseType = getParameterUpperBound(0, returnType as ParameterizedType)
        if (getRawType(responseType) != ApiResult::class.java) return null
        val dataType = getParameterUpperBound(0, responseType as ParameterizedType)
        return object : CallAdapter<Any, Call<ApiResult<Any>>> {
            override fun responseType() = dataType
            override fun adapt(call: Call<Any>) = ApiResultCall(call)
        }
    }
}

5. Converter 机制

5.1 Converter 接口

interface Converter<F, T> {
    fun convert(value: F): T?
}

abstract class Factory {
    open fun responseBodyConverter(type: Type, annotations: Array<Annotation>, retrofit: Retrofit): Converter<ResponseBody, *>? = null
    open fun requestBodyConverter(type: Type, paramAnnotations: Array<Annotation>, methodAnnotations: Array<Annotation>, retrofit: Retrofit): Converter<*, RequestBody>? = null
    open fun stringConverter(type: Type, annotations: Array<Annotation>, retrofit: Retrofit): Converter<*, String>? = null
}

5.2 GsonConverterFactory 源码解析

class GsonResponseBodyConverter<T>(
    private val gson: Gson,
    private val adapter: TypeAdapter<T>
) : Converter<ResponseBody, T> {
    override fun convert(value: ResponseBody): T? {
        val reader = gson.newJsonReader(value.charStream())
        return value.use {
            val result = adapter.read(reader)
            if (!reader.peek().equals(JsonToken.END_DOCUMENT)) {
                throw JsonIOException("JSON document was not fully consumed.")
            }
            result
        }
    }
}

5.3 序列化方案对比

维度GsonMoshikotlinx.serialization
Kotlin 支持一般好(codegen)原生
null 安全⚠️ 可能赋 null✅ 严格✅ 严格
默认值❌ 忽略✅ 支持✅ 支持
反射依赖可选
多平台✅ KMP
包大小~250KB~150KB~300KB

选型:新项目用 kotlinx.serialization;存量项目 Moshi codegen 是最佳升级路径。

5.4 自定义 Converter:拆包 BaseResponse

data class BaseResponse<T>(val code: Int, val message: String, val data: T?)
​
class UnwrapConverterFactory(private val inner: Converter.Factory) : Converter.Factory() {
    override fun responseBodyConverter(type: Type, annotations: Array<Annotation>, retrofit: Retrofit): Converter<ResponseBody, *>? {
        val wrappedType = TypeToken.getParameterized(BaseResponse::class.java, type).type
        val delegate = inner.responseBodyConverter(wrappedType, annotations, retrofit) ?: return null
        @Suppress("UNCHECKED_CAST")
        return Converter<ResponseBody, Any> { body ->
            val base = (delegate as Converter<ResponseBody, BaseResponse<Any>>).convert(body)
            if (base?.code != 0) throw ApiException(base?.code ?: -1, base?.message ?: "Unknown")
            base.data
        }
    }
}

6. 协程与 Flow 集成

6.1 suspend 函数支持原理

suspend fun <T> Call<T>.await(): T {
    return suspendCancellableCoroutine { continuation ->
        continuation.invokeOnCancellation { cancel() }
        enqueue(object : Callback<T> {
            override fun onResponse(call: Call<T>, response: Response<T>) {
                if (response.isSuccessful) {
                    continuation.resume(response.body()!!)
                } else {
                    continuation.resumeWithException(HttpException(response))
                }
            }
            override fun onFailure(call: Call<T>, t: Throwable) {
                continuation.resumeWithException(t)
            }
        })
    }
}

6.2 Flow 集成

// 分页
fun getPagedUsers(): Flow<List<User>> = flow {
    var page = 1
    while (true) {
        val users = api.getUsers(page = page, size = 20)
        if (users.isEmpty()) break
        emit(users)
        page++
    }
}
​
// 轮询
fun pollOrderStatus(orderId: String): Flow<OrderStatus> = flow {
    while (true) {
        emit(api.getOrderStatus(orderId))
        delay(3000)
    }
}.distinctUntilChanged()

6.3 错误处理

suspend fun <T> safeCall(block: suspend () -> T): ApiResult<T> {
    return try {
        ApiResult.Success(block())
    } catch (e: HttpException) {
        ApiResult.HttpError(e.code(), e.message())
    } catch (e: IOException) {
        ApiResult.NetworkError(e)
    }
}

7. 实战最佳实践

7.1 Token 刷新拦截器

class TokenRefreshInterceptor(private val tokenProvider: TokenProvider) : Interceptor {
    private val lock = Any()
​
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request().newBuilder()
            .header("Authorization", "Bearer ${tokenProvider.accessToken}")
            .build()
        val response = chain.proceed(request)
        if (response.code != 401) return response
​
        response.close()
        synchronized(lock) {
            val currentToken = tokenProvider.accessToken
            if (currentToken != request.header("Authorization")?.removePrefix("Bearer ")) {
                return chain.proceed(request.newBuilder()
                    .header("Authorization", "Bearer $currentToken").build())
            }
            if (!tokenProvider.refreshToken()) {
                tokenProvider.logout()
                throw TokenExpiredException("Token refresh failed")
            }
        }
        return chain.proceed(request.newBuilder()
            .header("Authorization", "Bearer ${tokenProvider.accessToken}").build())
    }
}

7.2 MockWebServer 测试

class UserApiTest {
    private val server = MockWebServer()
    private lateinit var api: UserApi
​
    @Before fun setup() {
        server.start()
        api = Retrofit.Builder().baseUrl(server.url("/"))
            .addConverterFactory(GsonConverterFactory.create())
            .build().create(UserApi::class.java)
    }
​
    @After fun tearDown() = server.shutdown()
​
    @Test fun `getUser returns parsed user`() = runTest {
        server.enqueue(MockResponse().setBody("""{ "id": 42, "name": "千寻" }""")
            .addHeader("Content-Type", "application/json"))
        val user = api.getUser(42)
        assertEquals(42, user.id)
        val recorded = server.takeRequest()
        assertEquals("/users/42", recorded.path)
    }
}

8. 总结

面试高频题

Q:Retrofit.create() 做了什么? A:通过 Java 动态代理创建接口实现类。调用方法时解析注解构建 ServiceMethod(缓存在 ConcurrentHashMap),创建 OkHttpCall 并通过 CallAdapter 适配返回类型。

Q:suspend 函数如何被 Retrofit 支持? A:不是通过 CallAdapter。HttpServiceMethod.parseAnnotations() 检测到 Continuation 参数时使用 SuspendForBody/SuspendForResponse 子类,内部通过 KotlinExtensions.await() 用 suspendCancellableCoroutine 桥接回调。

Q:Converter 的调用时机? A:请求时 requestBodyConverter 将 @Body 序列化为 RequestBody;响应时 responseBodyConverter 将 ResponseBody 反序列化为目标类型。按注册顺序遍历,第一个非 null 生效。

Q:Retrofit 和 OkHttp 的关系? A:Retrofit 是上层封装,负责接口定义、注解解析、类型转换;OkHttp 负责实际 HTTP 通信。Retrofit 最终把每个调用转成 OkHttpCall 委托给 OkHttpClient 执行。

Q:为什么 Token 刷新用 synchronized 而不用 Mutex? A:OkHttp 拦截器运行在线程池普通线程中。Mutex 需要 runBlocking 桥接,线程池耗尽时可能死锁。synchronized 在此场景更安全。

本文代码基于 Retrofit 2.9.x / OkHttp 4.x / Kotlin Coroutines 1.7.x,均已简化保留核心逻辑。