Retrofit原理
概论
当前版本com.squareup.retrofit2:retrofit:2.9.0
虽然okhttp
很好用,但是开发者所需要关心的细节太多了,所以square
又开发了retrofit
简化流程。
retrofit
主要使用流程如下:
interface GithubService {
@GET("users/{user}/repos")
fun listRepos(@Path("user") user: String): Call<List<String>>
}
val retrofit = Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build()
val service = retrofit.create(GithubService::class.java)
val repos = service.listRepos("octocat")
过程非常简单,但是有一些问题:
- 如何做到将接口转化为实现类?
- 如何将
retrofit
调用转化为okhttp
调用? - 如何从注解中获取信息填充到
request
? - 如何将
response
转化为相应的实体类?
生成实现类
现在有target
这样一个类,target
有方法targetFunction
;现在有这样的需求,在不修改target
类源代码的前提下,在targetFunction
真正执行之前或者之后添加一些行为;由于不能修改target
的源代码,所以必须要新建一个类proxy
,去调用targetFunction
方法,并且添加行为;
这种设计模式被称为代理模式
,根据proxy
字节码文件是否先于编译期存在,分为 静态代理 和 动态代理;
静态代理
proxy
声明和target
一样的接口,并且拥有一个target
字段,然后再接口实现中调用target
的方法,并添加行为;
具体代码如下:
interface GithubService{
fun listRepos(user: String): List<String>
}
class Target : GithubService{
override fun listRepos(user: String): List<String>{
return listOf()
}
}
class Proxy : GithubService{
private val target = Target()
override fun listRepos(user: String): List<String>{
println("before invocation")
val result = target.listRepos(user)
println("after invocation")
return result
}
}
动态代理
静态代理的proxy
可以针对每个方法去提供特定实现,动态代理想要做到这一点,就需要知道当前在执行哪个方法,根据方法签名去提供特定实现;
所以动态代理需要三个东西:
- 约定实现的接口
- 针对接口方法提供实现的
InvocationHandler
- 该接口的原本实现类(可有可无)
具体代码如下:
interface GithubService{
fun listRepos(user: String): List<String>
}
class Target : GithubService{
override fun listRepos(user: String): List<String>{
return listOf()
}
}
class ProxyInvocationHandler(val target: Any) : InvocationHandler{
override fun invoke(proxy: Any?, method: Method?, args: Array<out Any>?): Any {
println("before invocation")
val result = method?.invoke(target, args)
println("after invocation")
return result
}
}
fun main(){
val invocationHandler = ProxyInvocationHandler(Target())
val proxy = Proxy.newProxyInstance(
GithubService::class.java.getClassLoader(),
arrayOf(GithubService::class.java),
invocationHandler
)
proxy.listRepos("octocat")
}
更加具体的过程,请查看这篇文章;
实现过程
Retrofit的构造过程
- Retrofit.Builder
builder
是retrofit
的建造者,其重要字段如下:
// 根据当前虚拟机的名称确定平台
// 提供CallAdapterFactory和ConverterFactory
private final Platform platform;
// 根据request发起请求的客户端,默认为OkHttpClient
private @Nullable okhttp3.Call.Factory callFactory;
// 域名
private @Nullable HttpUrl baseUrl;
// 完成实体类到requestBody的转换,responseBody到实体类的转换的工厂
private final List<Converter.Factory> converterFactories = new ArrayList<>();
// 根据返回值决定Call的执行方式的工厂
private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
// 回调执行的位置
private @Nullable Executor callbackExecutor;
// 如果为true,retrofit.create()会完成所有方法的ServiceMethod的创建
private boolean validateEagerly;
建造过程:
public Retrofit build() {
// 必须要定义域名
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
// 默认由OkHttpClient发起请求
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
// 内部调用Handler在主线程执行回调
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// 先匹配自定义的工厂
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories =
new ArrayList<>(
1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
// Add the built-in converter factory first. This prevents overriding its behavior but also
// ensures correct behavior when using converters that consume all types.
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(platform.defaultConverterFactories());
return new Retrofit(
callFactory,
baseUrl,
unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories),
callbackExecutor,
validateEagerly);
}
CallAdapter.Factory
这个类只有一个抽象方法:
根据返回值返回CallAdapter
public abstract @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit);
默认有两个实现类CompletableFutureCallAdapterFactory
和DefaultCallAdapterFactory
;
该方法在DefaultCallAdapterFactory
中的实现如下:
@Override
public @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit) {
// 只适配Call<T>
if (getRawType(returnType) != Call.class) {
return null;
}
// 一定要指定泛型
if (!(returnType instanceof ParameterizedType)) {
throw new IllegalArgumentException(
"Call return type must be parameterized as Call<Foo> or Call<? extends Foo>");
}
// 获取泛型上界
final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);
// 根据注解获取executor
final Executor executor =
Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
? null
: callbackExecutor;
// 匿名对象
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);
}
};
}
CompletableFutureCallAdapterFactory
的实现也是相似的,不在赘述;
CallAdapter
// R 代表 ResponseBody 对应的实体类
// T 代表 Call 的代理类,有两种情况
// 1. Call<R>本身
// 2. CompletableFuture<R>
public interface CallAdapter<R, T> {
/**
* 在responseBody转化为实体类时会调用,一般返回R代表的类型
*/
Type responseType();
/**
* 根据call返回T
*/
T adapt(Call<R> call);
}
Converter.Factory
// 定义了RequestBody和ResponseBody转换的函数
abstract class Factory {
// 由ResponseBody转化为对应实体类
public @Nullable Converter<ResponseBody, ?> responseBodyConverter(
Type type, Annotation[] annotations, Retrofit retrofit) {
return null;
}
/**
* 将由 @Body,@Part,@PartMap注解的参数转化为RequestBody
*/
public @Nullable Converter<?, RequestBody> requestBodyConverter(
Type type,
Annotation[] parameterAnnotations,
Annotation[] methodAnnotations,
Retrofit retrofit) {
return null;
}
/**
* 对应类型转化为String
*/
public @Nullable Converter<?, String> stringConverter(
Type type, Annotation[] annotations, Retrofit retrofit) {
return null;
}
}
默认实现有BuiltInConverters
和OptionalConverterFactory
;
Converter
// 定义了一个从F转化到T的函数
public interface Converter<F, T> {
@Nullable
T convert(F value) throws IOException;
}
一共有七个实现类,分布在BuiltInConverters
和OptionalConverterFactory
中,实现也都很简单,不再说明;
InvocationHandler
InvocationHandler
包含了对每个接口方法的处理,代码如下:
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// 该方法在Object类中声明,则直接调用
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
args = args != null ? args : emptyArgs;
// 如果该方法是default方法(在Java8里添加),则调用default方法;
// 否则生成ServiceMethod调用invoke方法;
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
ServiceMethod
ServiceMethod
是一个抽象类,代码如下:
abstract class ServiceMethod<T> {
// 处理注解,生成ServiceMethod的实现类
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
// 处理注解,获得关于request的信息
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, 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);
}
// 传入参数,调用接口方法,返回Call<R>,或CompletableFuture<R>
abstract @Nullable T invoke(Object[] args);
}
ServiceMethod
有一个抽象子类HttpServiceMethod
,重要字段如下:
// 保存request的信息
private final RequestFactory requestFactory;
// 真正发起请求的客户端
private final okhttp3.Call.Factory callFactory;
// 将ResponseBody转化为指定类型
private final Converter<ResponseBody, ResponseT> responseConverter;
HttpServiceMethod
实现了invoke
抽象方法,并且添加了一个新的抽象方法;
@Override
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);
HttpServiceMethod
又有三个子类:CallAdapted
,SuspendForResponse
和SuspendForBody
;
根据isKotlinSuspendFunction
分为两类,后面一类支持协程,isKotlinSuspendFunction
来自RequestFactory
,具体过程稍后说明;
CallAdapted
代码如下:
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);
}
}
只是简单调用了CallAdapter
进行转换;
RequestFactory
RequestFactory
可以算是一个工具类,从Method
中获取所有的注解,然后将注解中的信息分离出来;
其主要工作都是RequestFactory.Builder
完成的,处理两类注解:方法注解和参数注解;具体细节请看源码,但是有几点需要提醒:
- 方法注解主要是对相对路径的完善,也就是报文中的请求行;
- 参数注解主要是对请求头和请求体的完善;
- 对于最后一个参数,会进行特殊处理,判断其类型是不是
Continuation
,然后为isKotlinSuspendFunction
赋值;为什么是最后一个参数?是因为kotlin
中的挂起函数,在编译过程中,会在函数的参数列表中添加一个Continuation
以实现其功能;
结论
其实还有好多细节没有讲清,比如RequestFacotry
的具体工作过程、代码内各种关于Type
的判断等等,但是对于理解Retrofit
整体工作过程是足够了;
总结一下,Retrofit
的工作过程如下:
- 配置Retrofit,获得
CallAdapter.Factory
列表和Converter.Factory
列表等其他信息; - 通过动态代理生成代理类;
- 通过
RequestFactory
获得request
所需信息; - 最终通过
ServiceMethod
的子类发送请求;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】