1. Retrofit 核心原理解析
本章深入 Retrofit 的底层运行机制,涵盖动态代理、注解解析、CallAdapter 与 Converter 的协作模式,以及一次完整 HTTP 请求从接口定义到网络响应的执行流程。掌握这些原理是后续进行高级配置、性能优化和错误排查的基础。
1.1 整体架构流程
Retrofit 本质上是一个接口驱动的 HTTP 客户端封装库:开发者只定义 Java 接口与方法注解,Retrofit 在运行时通过 动态代理 生成代理对象,调用时解析注解、构建请求、交由 OkHttp 执行,再通过 Converter 反序列化响应体,最后通过 CallAdapter 适配为所需返回类型(如 Call、LiveData、RxJava 等)。
核心思想: Retrofit 将网络请求的声明(注解)与执行(OkHttp)解耦,使开发者只需关注业务接口,无需关心 HTTP 通信细节。
1.2 动态代理机制
Retrofit 通过 java.lang.reflect.Proxy 为每个用户定义的接口生成代理对象。当调用任意方法时,代理的 invoke() 方法被触发,其中包含了完整的方法元数据。
// Retrofit 内部简化示意(非实际源码)
public class Retrofit {
public <T> T create(final Class<T> service) {
return (T) Proxy.newProxyInstance(
service.getClassLoader(),
new Class<?>[] { service },
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) {
// 1. 解析方法上的注解(@GET、@POST 等)
// 2. 解析参数注解(@Query、@Body、@Path 等)
// 3. 构建 ServiceMethod 对象
// 4. 通过 OkHttp 执行或返回 Call
}
}
);
}
}
关键点: 每次调用接口方法都会触发代理的 invoke,但 Retrofit 内部会缓存解析后的 ServiceMethod,避免重复注解解析开销。
1.3 注解解析与参数绑定
Retrofit 支持多种 HTTP 方法注解(@GET、@POST、@PUT、@DELETE、@PATCH、@HEAD、@OPTIONS)和参数注解。注解处理器在第一次调用时解析并缓存为 ServiceMethod。
| 注解类别 | 常用注解 | 作用 |
|---|---|---|
| HTTP 方法 | @GET、@POST、@PUT、@DELETE | 指定请求方法 |
| URL 占位 | @Path("id") | 替换路径中的 {id} |
| 查询参数 | @Query("page") | 追加 ?page=value |
| 请求体 | @Body | 序列化对象为请求 body |
| 请求头 | @Header("Authorization") | 添加请求 Header |
| 表单字段 | @Field("name") | 配合 @FormUrlEncoded 使用 |
| 多部分 | @Part("file") | 配合 @Multipart 上传文件 |
// 示例:接口定义
public interface GithubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(
@Path("user") String user,
@Query("sort") String sort,
@Query("per_page") int perPage
);
}
1.4 CallAdapter 与 Converter 协作
CallAdapter 负责将 OkHttp 的 Call 转换为开发者期望的返回类型(如 LiveData、RxJava Observable、Kotlin suspend 等)。Converter 负责将网络数据流与 Java 对象互相转换。
// 添加 Gson Converter 和 RxJava CallAdapter
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
执行顺序: 响应流先经过 Converter 反序列化为 Java 对象,再经过 CallAdapter 包装为返回类型。Retrofit 内部按添加顺序遍历工厂,直到找到能处理的适配器。
1.5 请求与响应完整流程
- 创建代理:
retrofit.create(Api.class)返回动态代理实例。 - 方法调用:调用接口方法(如
api.listRepos("octocat", "updated", 10))。 - 解析 & 缓存:
ServiceMethod解析注解、参数,生成RequestBuilder。 - 构建 OkHttp Request:组装 URL、Header、Body、Query 等。
- 执行网络请求:OkHttp 发起同步或异步 HTTP 请求。
- 获取原始 Response:OkHttp 返回
ResponseBody(字节流)。 - Converter 反序列化:将
ResponseBody转为List<Repo>等 Java 对象。 - CallAdapter 转换:将
Call<List<Repo>>转为Observable<List<Repo>>或LiveData等。 - 返回/回调:最终结果通过回调或观察者传递到调用方。
1.6 常见错误与调优建议
常见错误:
- 未添加 Converter 工厂导致
java.lang.IllegalArgumentException: Unknown class as response type。 - 接口路径未以
/开头导致 URL 拼接错误。 - 使用
@QueryMap时 Map 的 value 类型非 String 导致序列化异常。 - CallAdapter 工厂顺序错误,导致类型不匹配。
// 错误示例:缺少 Converter
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.example.com/")
.build(); // 没有加 addConverterFactory,请求时会抛出异常
稳定性优化: 将 Retrofit 实例设为单例;对 OkHttpClient 的超时、重试、缓存进行统一配置;使用自定义 CallAdapter 统一错误处理和线程切换。