前言
Retrofit是什么?
Retrofit是一个restful的HTTP网络请求框架的封装;
那为什么起名叫Retrofit呢?
Retrofit翻译为中文,意为改造、翻新之意,Retrofit网络请求的本质是交给内部的OkHttp来完成的,自身只负责网络请求接口的封装,这样一想,名字起的真是十级👍;
我们先简单看下Retrofit工作流程图:
APP应用端通过Retrofit请求网络,实际上是使用Retrofit接口层封装请求参数,如Header、Url等信息,之后交给OkHttp完成后续的请求;
当服务端返回请求数据后,OkHttp将请求原始数据交给Retrofit,Retrofit根据用户需求对结果进行解析;
因此,网络请求的本质仍然是OkHttp实现的,Retrofit只是帮使用者进行了工作简化,比如配网入参、封装请求、解析数据等工作,提供了这一系列的复用性;
Retrofit请求原理解析
在分析Retrofit请求原理之前,我们先看下Retrofit是如何发起网络请求的?
代码示例
// 1.构建retrofit对象
val retrofit = Retrofit.Builder()
.baseUrl("https://www.wanandroid.com")
.addConverterFactory(GsonConverterFactory.create(Gson()))
.build()
// 2.通过动态代理构造请求Call
val loginService: ILoginService = retrofit.create(ILoginService::class.java)
val loginCall = loginService.login("123")
// 3.调用Call发起网络请求
loginCall.enqueue(object: retrofit2.Callback<User> {
override fun onResponse(
call: retrofit2.Call<User>,
response: retrofit2.Response<User>
) {
}
override fun onFailure(call: retrofit2.Call<User>, t: Throwable) {
}
})
接下来,我们就通过分析源码来看Retrofit是如何通过封装OkHttp从而发起网络请求的;
Retrofit源码分析
我们根据上面的使用方式,将整个网络请求分为以下三个主要步骤:
构建Retrofit对象
使用动态代理构造请求Call
通过Call发起网络请求
接下来,我们就围绕这三个主体步骤进行源码分析;
构建Retrofit对象
我们先看下Retrofit.build()源码里都做了什么?
public Retrofit build() {
//判断baseUrl 不可以为空
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
// 初始化请求Call,从命名看可能考虑后续拓展命名为工厂,但目前默认只支持OkHttp请求,不支持其他请求方式;
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
// 添加一个线程管理 executor,我们知道okhttp中请求结束后需要手动切换线程,而retrofit不需要,正是因为 callbackExecutor的存在,其实就是一个handler的封装
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// 将构建的callbackExecutor包装到callAdapterFactories集合中存储,以便后续使用;
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
// 默认添加 DefaultCallAdapterFactory类
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
// 构建转换器并包装到converterFactories集合中存储,这里以便后续使用;
List<Converter.Factory> converterFactories =
new ArrayList<>(
1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(platform.defaultConverterFactories());
return new Retrofit(
callFactory,
baseUrl,
unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories),
callbackExecutor,
validateEagerly);
}
其中platform.defaultCallbackExecutor具体代码如下:
static final class Android extends Platform {
@Override
public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
...
static final class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable r) {
handler.post(r);
}
}
}
可以看到仅仅是构造了主线程的Handler,用于后续线程切换使用;
我们再看看默认添加的 platform.defaultCallAdapterFactories(callbackExecutor)
List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
@Nullable Executor callbackExecutor) {
DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
return hasJava8Types
? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
: singletonList(executorFactory);
}
这里就是创建一个DefaultCallAdapterFactory用于后续OkHttp发起网络请求,我们后续再详细分析;
小结
Retrofit.build()使用建造者模式,做一些准备工作,主要如下:
baseUrl判空
构建OkHttpClient
构建CallAdapterFactory用于后续网络请求
构建ConverterFactory用于后续数据解析
动态代理构造请求Call
接下来我们继续分析这两行代码源码:
// 2.通过动态代理构造请求Call
val loginService: ILoginService = retrofit.create(ILoginService::class.java)
val loginCall = loginService.login("123")
1
2
3
其中retrofit.create源码如下:
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();
private final Object[] emptyArgs = new Object[0];
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
args = args != null ? args : emptyArgs;
// 根据方法生成一个serviceMethod对象【内部会将生成的ServiceMethod进行缓存处理】
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
1
其中serviceMethod.invoke(args)代码如下:
@Override
final @Nullable ReturnT invoke(Object[] args) {
// 根据ServiceMethod对象和请求参数生成一个OkHttpCall对象,用于后续调用OkHttp的接口发起网络请求
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
//调用adapt方法,并传入OkHttpCall,内部会进行包装,返回一个Call对象,用于后续网络请求
return adapt(call, args);
}
上述代码流程如下:
Retrofit.create()通过动态代理模式,生成了实现具体网络请求接口的对象,并在InvocationHandler.invoke方法中统一进行网络请求处理;
InvocationHandler.invoke中会构造一个ServiceMethod对象,并会做缓存处理;
根据ServiceMethod对象和网络请求参数args去构造一个OkHttpCall对象;
调用adapt(call, args)方法,主要是为了适配OkHttpCall对象,其内部会对OkHttpCall对象进行包装,生成对应返回类型的对象;
动态代理
动态代理:在运行时动态生成代理类,然后根据代理类生成一个代理对象,在这个代理对象的方法中又会调用InvocationHandler.invoke方法来转发对方法的处理。
我们在使用Retrofit的时候,对每一个网络请求的产生都必须先调用create函数,也就是意味着,我们的请求都是通过代理类来处理的,而代理类具体的代理行为是发生在哪里呢?很显然,并不是在create函数执行的时候,而是在使用具体的接口创建具体网络请求Call的时候,也就是对应如下这行代码:
val loginCall = loginService.login("123")
1
在执行上面代码的时候,它会走代理设计模式中的InvocationHandler.invoke方法,也就是所有的网络请求在创建具体网络请求call的时候,都会走InvocationHandler.invoke方法,而从我们可以在此方法里进行各种行为的统一处理,比如:接口的统一配置,也就是注解的解析和网络请求参数的拼接;
ServiceMethod
我们先看看loadServiceMethod方法
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;
}
loadServiceMethod首先会从缓存中获取ServiceMethod对象,如果没有,再通过parseAnnotations构造一个并缓存起来;
每一个method都有一个自己的ServiceMethod,也就是说我们定义的网络访问接口类,在接口类里面的每一个函数都会在反射阶段形成自己的servicemethod,那么ServiceMethod里面存放的是什么呢?
ServiceMethod其实是用来存储一次网络请求的基本信息,比如Host、URL、请求方法等,同时ServiceMethod还会存储用来适配OkHttpCall对象的CallAdapter,ServiceMethod的parseAnnotations方法会解析传入的method,首先ServiceMethod会在CallAdapterFactory列表中寻找合适的CallAdapter来包装OkHttpCall对象,这一步主要是根据Method的返回参数来匹配的,比如如果方法的返回参数是Call对象,那么ServiceMethod就会使用默认的CallAdapterFactory来生成CallAdapter,而如果返回对象是RxJava的Observable对象,则会使用RxjavaCallAdapterFactory提供的CallAdapter。
CallAdapter
我们考虑一下这个问题?为什么InvocationHandler.invoke方法不可以直接返回OKHttpCall对象,而是调用adapt(call, args)进行了适配器适配?
我们知道Retrofit真正使用OkHttp进行网络请求的就是OkHttpCall这个类;改动后也可以实现网络请求;
但是改动后的代码带来的后果之一就是:因为OkHttpCall实现了Call接口,API Service方法的返回值必须是Call<T>类型,直观表现如下所示:
public interface ILoginService {
@GET("user/login")
Call<User> login(String userId);
@GET("user/register")
Call<User> register(String userId);
@GET("user/update")
Call<User> update(String userId);
}
如果没有适配器的时候,我们网络请求返回接口只能直接返回OkHttpCall,那所有的网络请求都是用OkHttpCall进行,这样就失去了Retrofit封装的意义了,比如RxJava的Observable就无法支持了。
这里适配器模式发挥了作用,将网络请求的核心类OkHttpCall进行适配,你需要什么类型的数据就通过适配器适配,返回适配后的对象,正是这种CallAdapter接口的设计,使用我们在使用Retrofit的时候可以自定义我们想要的返回类型;
我们可以看下Retrofit默认采用的DefaultCallAdapterFactory中的源码:
final class DefaultCallAdapterFactory extends Factory {
static final Factory INSTANCE = new DefaultCallAdapterFactory();
DefaultCallAdapterFactory() {
}
@Nullable
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
} else {
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Object, Call<?>>() {
public Type responseType() {
return responseType;
}
//将OkHttpCall适配成Call对象并返回,也就是`InvocationHandler.invoke`最终的返回值
public Call<Object> adapt(Call<Object> call) {
return call;
}
};
}
}
}
我们再跟进下ServiceMethod.parseAnnotations方法;
### ServiceMethod.parseAnnotations方法
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method 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);
}
### HttpServiceMethod.parseAnnotations方法
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
//构造callAdapter,用于OkHttpCall转换
CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method);
Type responseType = callAdapter.responseType();
if (responseType == Response.class || responseType == okhttp3.Response.class) {
throw methodError(method, "'"
+ Utils.getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
throw methodError(method, "HEAD method must use Void as response type.");
}
//构造Converter,用于数据解析
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
//默认的OkHttpClient
okhttp3.Call.Factory callFactory = retrofit.callFactory;
return new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter);
}
整体看下来就是构造一个HttpServiceMethod对象,里面存放的内容如下:
requestFactory:解析注解构造的请求工厂数据,里面有method,baseUrl,httpMethod等等;
callFactory:默认为OkHttpClient对象;
callAdapter:用于适配OkHttpCall的适配器;
responseConverter:用于解析响应的converter;
调用OkHttpCall发起网络请求
通过上面的动态代理方法调用,我们已经构造了具备发起网络请求的Call,接下来就是发起最终的网络请求;
// 3.调用OkHttpCall发起网络请求
loginCall.enqueue(object: retrofit2.Callback<User> {
override fun onResponse(
call: retrofit2.Call<User>,
response: retrofit2.Response<User>
) {
}
override fun onFailure(call: retrofit2.Call<User>, t: Throwable) {
}
})
enqueue源码如下:
### ExecutorCallAdapterFactory.ExecutorCallbackCall.enqueue()方法
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
//delegate是Call类型,最终会调用OkHttpCall.enqueue发起网络请求,这里不在深入;
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
//通过callbackExecutor实现线程切换到主线程!!!
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}
@Override public void onFailure(Call<T> call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
}
1
这里就比较简单了,不再过多赘述,我们继续看下返回结果是如何通过前面提到的converter进行解析的;
Converter请求与返回数据转换
我们主要跟进下 response = parseResponse(rawResponse)这段源码:
### OkHttpCall.parseResponse()方法
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
...
try {
T body = responseConverter.convert(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
...
throw e;
}
}
responseConverter.convert是接口返回的调用,其实现类如下:
这里我们重点看下GsonRequestBodyConverter【请求数据转换】和GsonResponseBodyConverter【返回数据转换】
GsonRequestBodyConverter
final class GsonRequestBodyConverter<T> implements Converter<T, RequestBody> {
private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");
private static final Charset UTF_8 = Charset.forName("UTF-8");
private final Gson gson;
private final TypeAdapter<T> adapter;
GsonRequestBodyConverter(Gson gson, TypeAdapter<T> adapter) {
this.gson = gson;
this.adapter = adapter;
}
@Override public RequestBody convert(T value) throws IOException {
Buffer buffer = new Buffer();
Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
JsonWriter jsonWriter = gson.newJsonWriter(writer);
adapter.write(jsonWriter, value);
jsonWriter.close();
return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
}
}
1
GsonResponseBodyConverter
final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
private final Gson gson;
private final TypeAdapter<T> adapter;
GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
this.gson = gson;
this.adapter = adapter;
}
@Override public T convert(ResponseBody value) throws IOException {
JsonReader jsonReader = gson.newJsonReader(value.charStream());
try {
return adapter.read(jsonReader);
} finally {
value.close();
}
}
}
1
可以看到最终就是通过Gson的方法调用完成请求与返回数据的转换;
Retrofit整体网络请求流程图
总结
Retrofit将设计模式运用到了极致,涉及到的设计模式有动态代理、建造者、外观模式、适配器、装饰器等,其中动态代理更是整个网络请求的核心,Retrofit的源码看下来也比较流畅,真是不得不让人佩服!!