🎯 Retrofit 的核心定位:不是网络库,是“适配器”
很多人有个误区,觉得 Retrofit 是一个网络库。其实不是,它只是一个对网络请求的封装和适配。真正的脏活累活,都是交给 OkHttp 去干的。
它的核心价值在于:把你在 Java 接口里定义的方法和注解,转换成 OkHttp 能够发起的网络请求,再把 OkHttp 返回的 Response,通过你指定的转换器(如 Gson),解析成你想要的 Java 对象。
Retrofit 的本质流程可以概括为下图:
这个流程清晰地展示了 Retrofit 的三大阶段:设计时(注解)-> 运行时(动态代理构建请求)-> 执行时(OkHttp+转换器)。下面我们来逐一深入。
🏗️ 1. 创建 Retrofit 实例:搭建舞台
第一步就是通过 Builder 建造者模式创建 Retrofit 对象。
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create()) // 数据解析器
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // 返回值适配器
.client(okHttpClient) // 可配置自定义的 OkHttpClient
.build();
这一步的核心是把开发者的配置“固化”下来,形成一个可以生产网络请求的工厂。它内部维护了几个关键成员:
baseUrl:基础地址。converterFactories:数据转换器工厂列表。默认内置了内置的BuiltInConverters(处理ResponseBody、Void等),我们添加的GsonConverterFactory就在它前面。adapterFactories:返回值类型适配器工厂列表。默认会添加一个ExecutorCallAdapterFactory,用于将OkHttpCall适配成能在主线程回调的Call。callFactory:实际发起网络请求的工厂,默认是OkHttpClient。callbackExecutor:回调执行器,在 Android 上默认是MainThreadExecutor,通过Handler将回调切到主线程。
📝 2. 定义接口:编写剧本
这是 Retrofit 最迷人的地方。我们只需要定义一个 Java 接口,通过注解来“声明”一个网络请求。
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
这里的 @GET、@Path 注解就像是剧本的台词,描述了请求的所有要素。我们只关心“做什么”,而不关心“怎么做”。
🎭 3. 动态代理:核心戏法
当我们调用 retrofit.create(GitHubService.class) 时,神奇的事情发生了。它并没有返回一个我们写的实现类,而是通过 JDK 动态代理 在运行时生成了一个 GitHubService 的代理对象。
关键代码在 Retrofit#create 方法中:
public <T> T create(final Class<T> 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 的方法(如 equals、hashCode),直接调用
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
// 如果是接口的默认方法(Java 8),特殊处理
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
// 核心逻辑:加载/创建 ServiceMethod,并调用 adapt
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
这个 InvocationHandler 就是总导演。当我们调用 gitHubService.listRepos("square") 时,实际上执行的是这里的 invoke 方法。
⚙️ 4. 从注解到请求:ServiceMethod 和 OkHttpCall
loadServiceMethod(method) 会解析我们定义的 listRepos 方法。它采用了缓存机制,同一个方法只解析一次。
解析过程由 ServiceMethod.Builder 完成,主要包括:
- 解析方法注解:读取
@GET、@POST、@Headers等,确定请求方式、相对路径、是否有表单等。 - 解析参数注解:遍历方法的每一个参数,根据
@Path、@Query、@Body等注解,创建对应的ParameterHandler<?>。比如,@Path("user") String user会生成一个ParameterHandler.Path,它知道如何将user这个值替换到 URL 的占位符中。 - 确定 CallAdapter 和 Converter:
- 根据方法返回值类型(如
Call<List<Repo>>),从adapterFactories中找到一个能处理该类型的CallAdapter。 - 根据
CallAdapter解析出的响应类型(List<Repo>),从converterFactories中找到一个能将ResponseBody转换成List<Repo>的Converter。
- 根据方法返回值类型(如
- 构建 RequestFactory:将所有解析出的信息(URL、Headers、ParameterHandlers 等)封装成一个
RequestFactory,它的职责就是根据传入的参数(args)最终构建出一个okhttp3.Request。
解析完成后,我们就得到了一个 ServiceMethod 对象。它持有 CallAdapter、ResponseConverter 和 RequestFactory。接着,我们用它和传入的参数(args)创建一个 OkHttpCall。OkHttpCall 是 Retrofit 对 okhttp3.Call 的封装,负责实际执行网络请求。
最后一步,也是体现其扩展性的关键:serviceMethod.callAdapter.adapt(okHttpCall)。
- 如果我们返回值是
Call<T>,默认的ExecutorCallAdapterFactory会返回一个ExecutorCallbackCall,它内部将OkHttpCall的异步请求结果通过callbackExecutor(主线程Handler)回调给用户,实现了线程切换。 - 如果我们添加了
RxJava2CallAdapterFactory,返回值是Observable<T>,那么它会返回一个Observable,当OkHttpCall执行成功后,通过RxJava的Emitter发射数据。
🌐 5. 请求与解析:真正的网络交互
当我们调用 call.enqueue(callback) 时,最终会执行到 OkHttpCall 的 enqueue 方法。它内部会调用 createRawCall(),这个方法利用 serviceMethod 的 RequestFactory 和传入的参数,通过 ParameterHandler 逐个设置参数,最终构建出一个 okhttp3.Request,然后用 OkHttpClient 发起异步请求。
当 OkHttp 返回 okhttp3.Response 后,OkHttpCall 会调用 parseResponse 方法。如果响应成功(code 200),它会调用 serviceMethod.toResponse(catchingBody)。这个方法里就是 responseConverter.convert(catchingBody),将网络返回的二进制数据通过我们配置的 GsonConverterFactory 解析成 List<Repo> 对象。
最终,这个解析好的对象,会通过之前 CallAdapter 设定的线程模型,回调到我们的 onResponse 或 onNext 方法中。
💎 总结
Retrofit 的设计精髓在于将不变的部分(框架流程)和变化的部分(数据格式、调用平台)通过接口彻底解耦。
- 动态代理:优雅地拦截接口方法调用,将静态的注解转化为动态的请求描述。
- 建造者模式:构建复杂的
Retrofit对象。 - 工厂模式:
CallAdapter.Factory和Converter.Factory提供了无限制的扩展能力,想支持 Protobuf?加个转换器就行。想支持 LiveData?写个适配器就行。 - 装饰者模式:
ExecutorCallbackCall对OkHttpCall进行包装,增加了线程切换的功能。
所以,Retrofit 能成为事实标准,不是因为它发明了新的网络请求方式,而是因为它用最简洁、最稳定的方式,将各种优秀的库(OkHttp, Gson, RxJava)整合在了一起,让开发者能以一种近乎优雅的方式去写网络请求。