Retrofit源码解析
Retrofit是一个RESTFUL的HTTP网络请求框架(基于OkHttp)。
Retrofit的具体流程如下:
- 创建Retrofit实例
- 创建网络请求接口的实例(通过解析注解配置网络请求参数)
- 发送网络请求
- 解析数据
- 切换线程
- 处理结果
下来我们一一进行讲解。
一、创建Retrofit实例
通过内部类Builder(建造者模式)创建出一个Retrofit实例,其具体创建过程配置了一下参数:
- 平台类型对象(Platform—Android)
- 网络请求的url地址(baseUrl)
- 网络请求工厂(callFactory)—默认使用OkHttpCall
- 网络请求适配器工厂的集合(adapterFactories)—默认是ExecutorCallAdapterFactory
- 数据转换器工厂集合(converterFactories)—本质是配置了数据转换器工厂
- 回调方法执行器(callbackExecutor)—默认回调方法执行器的作用是:切换线程(子线程→主线程)
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
如何生成一个Retrofit实例,我们只需看build方法即可:
public Retrofit build() {
//检查网络请求的url是否为空,假如为空直接抛出异常。
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
//配置网络请求工厂(callFactory)
okhttp3.Call.Factory callFactory = this.callFactory;
//如果在创建实例时没有指定callFactory,默认使用OkHttp进行网络请求
if (callFactory == null) {
callFactory = new OkHttpClient();
}
//配置回调方法执行器(callbackExecutor)
Executor callbackExecutor = this.callbackExecutor;
//如果在创建实例时没有指定callbackFactory,默认使用Platform的默认的callbackFactory
//我们安卓开发就是Android平台默认的callbackExecutor
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
//配置网络请求适配器工厂(CallAdapterFactories)
//向该集合中添加创建实例时的自定义适配器工厂
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
//向该集合中 添加platform默认的适配器工厂
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
//请求适配器工厂集合存储顺序:自定义 1 适配器工厂、自定义 2 适配器工厂...默认适配器工厂(ExecutorCallAdapterFactory)
//配置数据转换器工厂(converterFactory)
//实现创建好大小合适的Converter.Factory集合
List<Converter.Factory> converterFactories =
new ArrayList<>(
1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
//依次添加默认数据转换器工厂(BuiltInConverters()),自定义工厂(this.converterFactories),平台默认数据转换器工厂(platform.defaultConverterFactories())
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(platform.defaultConverterFactories());
//最终返回一个 Retrofit 的对象,并传入上述已经配置好的成员变量
return new Retrofit(
callFactory,
baseUrl,
unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories),
callbackExecutor,
validateEagerly);
}
二、创建网络请求接口的实例(通过解析注解配置网络请求参数)
Retrofit采用了外观模式统一调用创建网络请求接口实例和网络请求参数配置的方法,具体过程如下:
- 动态创建网络请求接口(代理模式—动态代理#invocationHandler对象#invoke())
- 创建ServiceMethod对象(建造者模式&单例模式(缓存机制))
- 对serviceMethod对象进行网络请求参数配置:通过解析网络请求接口方法的参数、返回值和注解类型,从Retrofit对象中获取对应的网络请求的url地址、网络请求执行器、网络请求适配器和数据转换器(策略模式)
- 创建一个OkHttpCall类型的网络请求对象
- 对OkHttpCall对象加入线程切换的操作,便于接受数据后通过Handler从子线程切换到主线程从而对返回的数据结果进行处理(装饰模式)
GitHubService service = retrofit.create(GitHubService.class);
//listRepos是GitHubService.class中的一个方法
Call<List<Repo>> repos = service.listRepos("octocat");
表面看我们只写了短短两行,但实际内部做了很多处理!!!
步骤1.动态创建网络请求接口
public <T> T create(final Class<T> service) {
//1.检验service的方法,具体请看下方validateServiceInterface(service)方法的讲解。
validateServiceInterface(service);
//通过动态代理创建了网络请求接口的实例
return (T)
Proxy.newProxyInstance(
service.getClassLoader(),//动态生成接口的实现类
new Class<?>[] {
service},//动态创建实例
new InvocationHandler() {
//将代理类的实现交给InvocationHandler类作为具体实现
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
@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;
//2.如果该方法是默认方法也直接调用,否则加载该方法(loadServiceMethod()返回的是一个ServiceMethod对象)后再调用(实质就是进行网络请求)
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
注释1: 验证Service类的方法
private void validateServiceInterface(Class<?> service) {
//检验service是不是接口,如果不是抛出异常
if (!service.isInterface()) {
throw new IllegalArgumentException("API declarations must be interfaces.");
}
//检验service以及其所有的父接口是否具有泛型,如果有抛出异常
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());
}
//初始化所有service中非静态方法和非默认方法。
if (validateEagerly) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods())