Retrofit
是一个restful
的HTTP
网络请求框架的封装;
那为什么起名叫Retrofit
呢?
Retrofit
翻译为中文,意为改造
、翻新
之意,Retrofit
网络请求的本质是交给内部的OkHttp
来完成的,自身只负责网络请求接口的封装,这样一想,名字起的真是十级;
我们先简单看下Retrofit
工作流程图:
Retrofit
请求网络,实际上是使用Retrofit
接口层封装请求参数,如Header
、Url
等信息,之后交给OkHttp
完成后续的请求;OkHttp
将请求原始数据交给Retrofit
,Retrofit
根据用户需求对结果进行解析;因此,网络请求的本质仍然是OkHttp
实现的,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.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
用于后续数据解析接下来我们继续分析这两行代码源码:
// 2.通过动态代理构造请求Call
val loginService: ILoginService = retrofit.create(ILoginService::class.java)
val loginCall = loginService.login("123")
其中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);
}
});
}
其中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")
在执行上面代码的时候,它会走代理设计模式中的InvocationHandler.invoke
方法,也就是所有的网络请求在创建具体网络请求call的时候,都会走InvocationHandler.invoke
方法,而从我们可以在此方法里进行各种行为的统一处理,比如:接口的统一配置,也就是注解的解析和网络请求参数的拼接;
我们先看看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。
我们考虑一下这个问题?为什么InvocationHandler.invoke
方法不可以直接返回OKHttpCall
对象,而是调用adapt(call, args)
进行了适配器适配?
我们知道Retrofit
真正使用OkHttp进行网络请求的就是OkHttpCall这个类;改动后也可以实现网络请求;
但是改动后的代码带来的后果之一就是:因为OkHttpCall实现了Call接口,API Service方法的返回值必须是Call
类型,直观表现如下所示:
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;通过上面的动态代理
方法调用,我们已经构造了具备发起网络请求的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);
}
});
}
});
}
}
这里就比较简单了,不再过多赘述,我们继续看下返回结果是如何通过前面提到的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());
}
}
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();
}
}
}
可以看到最终就是通过Gson的方法调用
完成请求与返回数据的转换;
Retrofit
将设计模式运用到了极致,涉及到的设计模式有动态代理
、建造者
、外观模式
、适配器
、装饰器
等,其中动态代理
更是整个网络请求的核心,Retrofit
的源码看下来也比较流畅,真是不得不让人佩服!!!
后面我们继续学习Retrofit
中涉及到的设计模式Retrofit原理解析(二)
如果以上文章对您有一点点帮助,希望您不要吝啬的点个赞加个关注,您每一次小小的举动都是我坚持写作的不懈动力!ღ( ´・ᴗ・` )