Retrofit源码分析&小结
简介
Retrofit是对Okhttp网络请求的二次封装,通过注解+动态代理的方式,简化了Okhttp的使用,使得通过简单的配置就可以像调用接口一样去请求网络接口;除此之外Retrofit还支持RxJava和kotlin的协程
基本使用
引入依赖库
//网络请求
implementation 'com.squareup.retrofit2:retrofit:2.9.0'//Retrofit基本库
implementation 'com.squareup.retrofit2:converter-gson:2.1.0'//用于将结果转换成对象
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'//用于转换成RxJava支持的Observer对象
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'//RxJava对Android的支持
implementation 'com.squareup.okhttp3:logging-interceptor:3.9.0'//Okhttp日志拦截器,用于打印接口请求相关log
//协程
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4'//Retrofit对Kotlin协程的支持
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'//协程对Android的支持
implementation('androidx.lifecycle:lifecycle-runtime-ktx:2.6.0-alpha02')//协程对LifeCycle的支持
定义一个用于网络请求的服务接口
package com.example.myapplication.retrofit
import android.service.autofill.UserData
import io.reactivex.Observable
import retrofit2.Call
import retrofit2.http.*
interface IUserServer {
/**
* 以GET方式请求
*/
@GET("getUserInfo/")
fun getUserInfo(@Query("userId") userId: String): Call
/**
* 以POST方式请求,并结合RxJava
*/
@POST("getUserInfo/")
@FormUrlEncoded
fun getUserInfoByRxJava(@Field("userId") userId: String): Observable
/**
* 结合kotlin协程完成线程切换
*/
@GET("banner/json")
suspend fun getUserInfoBySuspend2(@Query("userId") userId: String): UserData
}
创建Retrofit对象和自定义接口代理实现对象
val retrofit = Retrofit.Builder()
.baseUrl("http://www.xxx.com/")
.addConverterFactory(GsonConverterFactory.create())//支持Gson
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())//支持Rxjava
.build()
val server = retrofit.create(IUserServer::class.java)
普通发起网络请求
val userInfo = server.getUserInfo("1").execute()//同步执行
server.getUserInfo("1").enqueue(object : Callback
override fun onResponse(call: Call
//网络请求返回结果
}
override fun onFailure(call: Call
//网络请求错误
}
})
结合RxJava
server.getUserInfoByRxJava("1").subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Observer
override fun onSubscribe(d: Disposable?) {
//网络请求前
}
override fun onNext(value: UserData?) {
//网络请求返回结果
}
override fun onError(e: Throwable?) {
//网络请求错误
}
override fun onComplete() {
//网络请求结束
}
})
结合Kotlin协程
lifecycleScope.launch {
val userInfo = withContext(Dispatchers.IO) {
val userInfo = server.getUserInfoBySuspend2("1")//子线程中请求网络
}
//回到主线程
Log.i("testRetrofit", "userInfo:$userInfo")
}
核心源码分析
1. Retrofit.create方法,根据注解为我们声明的接口创建动态代理
```
public
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;
return platform.isDefaultMethod(method)//判断该方法是否用户自定义的
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);//开始解析该方法并返回接口请求对象,比如Call、Observable(需结合Rxjava)
}
});
}
```
在validateServiceInterface方法中,如果配置了Retrofit.Builder().validateEagerly(true),会立刻根据注解解析接口中定义的所有方法,如果是false,则会等待方法调用时才会解析接口中的方法; 设置为true的好处是在创建接口代理时就能检查出各个方法配置的注解、返回值等是否正确,如果为默认的false,则只有在方法调用时才能发现问题; 所以建议在debug阶段设置为true便于及早发现问题,release阶段设置false以提高性能 private void validateServiceInterface(Class> service) {
... ...
if (validateEagerly) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {//遍历所有方法,根据注解进行解析
if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
loadServiceMethod(method);
}
}
}
}
默认实现中接口返回的Call实际上是一个Retrofit中定义的一个接口,定义了同步请求和异步请求的方法; public interface Call
... ...
/**
* Synchronously send the request and return its response.
*
* @throws IOException if a problem occurred talking to the server.
* @throws RuntimeException (and subclasses) if an unexpected error occurs creating the request or
* decoding the response.
*/
Response
/**
* Asynchronously send the request and notify {@code callback} of its response or if an error
* occurred talking to the server, creating the request, or processing the response.
*/
void enqueue(Callback
... ...
}
Call的实现类根据是否有注解@SkipCallbackExecutor来决定,当有该注解时,Call的实现类是OkHttpCall.java,里面封装了OkHttp的网络请求,如果没有该注解,则Call实现类是DefaultCallAdapterFactory.ExecutorCallbackCall;这个类仅仅是个代理类,真正实现网络请求的还是OkHttpCall; 代理类存在的意义是Okhttp进行异步请求返回结果后,会先通过Handler将线程切换到主线程再返回结果 final class OkHttpCall
@Override
public void enqueue(final Callback
...
okhttp3.Call call;
call.enqueue(
new okhttp3.Callback() {
@Override
public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
}
@Override
public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}
}
...
}
@Override
public Response
okhttp3.Call call;
...
return parseResponse(call.execute());
}
}
static final class ExecutorCallbackCall
final Executor callbackExecutor;//在主线程执行,实现类是Platform.Android.MainThreadExecutor
final Call
@Override
public void enqueue(final Callback
delegate.enqueue(
new Callback
@Override
public void onResponse(Call
callbackExecutor.execute(() -> {
//切换到主线程执行
callback.onResponse(ExecutorCallbackCall.this, response);
}
});
}
@Override
public void onFailure(Call
//切换到主线程执行
callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
}
});
}
@Override
public Response
return delegate.execute();//在当前所在线程执行
}
}
2. 注解的解析过程和使用
在Retrofit.create方法中,loadServiceMethod方法中会先从缓存中查找ServiceMethod对象,如果之前有解析过则直接返回,如果没有则调用ServiceMethod.parseAnnotations方法返回一个ServiceMethod对象 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;
}
接着会调用RequestFactory.parseAnnotations方法真正进行注解的解析,并构建一个HttpServiceMethod对象返回 abstract class ServiceMethod
static
//真正解析方法上的注解入口
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);
}
RequestFactory.Builder中解析方法中的注解,可以理解为RequestFactory对象保存着所有请求的数据 final class RequestFactory {
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
static final class Builder {
final Annotation[] methodAnnotations;//方法上的注解
final Annotation[][] parameterAnnotationsArray;//方法参数上的注解
final Type[] parameterTypes;//参数类型
@Nullable String httpMethod;//请求的方式get、post等
@Nullable String relativeUrl;//解析处理后的请求接口
@Nullable Headers headers;//封装的请求头信息
boolean isKotlinSuspendFunction; //用于标记是否kotlin协程中suspend方法
...
private Headers parseHeaders(String[] headers) {}//解析请求头信息
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) //解析请求方式和接口路径
private void parseMethodAnnotation(Annotation annotation) {//解析方法上的注解
if (annotation instanceof DELETE) {
parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
} else if (annotation instanceof GET) {
parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
} else if (annotation instanceof HEAD) {
parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
} else if (annotation instanceof PATCH) {
parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
} else if (annotation instanceof POST) {
parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
} else if (annotation instanceof PUT) {
parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
}
...
}
private ParameterHandler> parseParameterAnnotation(){//解析参数上注解
if (annotation instanceof Path) {
} else if (annotation instanceof Query) {
} else if (annotation instanceof QueryName) {
} else if (annotation instanceof QueryMap) {
} else if (annotation instanceof Header) {
} else if (annotation instanceof HeaderMap) {
} else if (annotation instanceof Field) {
} else if (annotation instanceof FieldMap) {
} else if (annotation instanceof Body) {
}
...
}
}
}
请求参数的使用,是在真正发起网络请求OkhttpCall.createRawCall()方法中创建Okhttp Call对象的时候,通过RequestFactory.create方法将所有请求参数封装成OkHttp的Request对象
class OkHttpCall{
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
return call;
}
}
class RequestFactory{
okhttp3.Request create(Object[] args) throws IOException {
RequestBuilder requestBuilder =
new RequestBuilder(
httpMethod,
baseUrl,
relativeUrl,
headers,
contentType,
hasBody,
isFormEncoded,
isMultipart);
if (isKotlinSuspendFunction) {//协程suspen方法会自动在最后面加一个Continuation对象类型参数,所以实际请求时要去掉
// The Continuation is the last parameter and the handlers array contains null at that index.
argumentCount--;
}
List
for (int p = 0; p < argumentCount; p++) {
argumentList.add(args[p]);
handlers[p].apply(requestBuilder, args[p]);
}
//构建okhttp3.Request对象
return requestBuilder.get().tag(Invocation.class, new Invocation(method, argumentList)).build();
}
}
3. RxJava2CallAdapterFactory:对Rxjava的支持,将默认返回的的Call对象转换成Observer对象
当调用接口方法的时候,通过动态代理默认会调用HttpServiceMethod.CallAdapted的invoke方法,而CallAdapted继承自HttpServiceMethod,并重写了adapt方法; adapt方法用于封装Call对象并将结果转化成我们定义的接口方法所声明的返回对象
class HttpServiceMethod{
@Override
final @Nullable ReturnT invoke(Object[] args) {
Call
return adapt(call, args);
}
protected abstract @Nullable ReturnT adapt(Call
static final class CallAdapted
private final CallAdapter
CallAdapted(
RequestFactory requestFactory,
okhttp3.Call.Factory callFactory,
Converter
CallAdapter
super(requestFactory, callFactory, responseConverter);
this.callAdapter = callAdapter;//通过RxJava2CallAdapterFactory生成的Rxjava2适配器RxJava2CallAdapter
}
@Override
protected ReturnT adapt(Call
return callAdapter.adapt(call);//调用适配器,将返回结果转换成我们定义的返回类型,比如默认是返回Call,Rxjava返回的是Observer对象
}
}
}
RxJava2CallAdapterFactory在创建时,可以选择调用create、createAsync、createWithScheduler(Scheduler)方法进行创建,他们的主要区别是create是调用Call.execute方法请求网络,也就是在当前线程执行; 而createAsync则是调用Call.enqueue方法请求网络,也就是异步请求;createWithScheduler可以传入一个Scheduler,指定网络请求在哪个线程上执行,通过observable.subscribeOn(scheduler)实现
public final class RxJava2CallAdapterFactory extends CallAdapter.Factory {
/**
* Returns an instance which creates synchronous observables that do not operate on any scheduler
* by default.
*/
public static RxJava2CallAdapterFactory create() {
return new RxJava2CallAdapterFactory(null, false);
}
/**
* Returns an instance which creates asynchronous observables. Applying
* {@link Observable#subscribeOn} has no effect on stream types created by this factory.
*/
public static RxJava2CallAdapterFactory createAsync() {
return new RxJava2CallAdapterFactory(null, true);
}
public static RxJava2CallAdapterFactory createWithScheduler(Scheduler scheduler) {
if (scheduler == null) throw new NullPointerException("scheduler == null");
return new RxJava2CallAdapterFactory(scheduler, false);
}
@Override
public CallAdapter, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
...
return new RxJava2CallAdapter(responseType, scheduler, isAsync, isResult, isBody, isFlowable,
isSingle, isMaybe, false);
}
}
调用RxJava2CallAdapter.adapt方法,将Call传入并返回Observer
final class RxJava2CallAdapter
@Override public Object adapt(Call
Observable
? new CallEnqueueObservable<>(call)
: new CallExecuteObservable<>(call);//真正网络请求包装在在这里面
...
Observable> observable;
if (isResult) {
observable = new ResultObservable<>(responseObservable);
} else if (isBody) {
observable = new BodyObservable<>(responseObservable);
} else {
observable = responseObservable;
}
if (scheduler != null) {
observable = observable.subscribeOn(scheduler);
}
...
return observable;
}
}
当外部调用Observer的subscribe方法时,后就会立刻执行CallExecuteObservable/CallExecuteObservable里的subscribeActual方法,从而调用Call的execute或者enqueue方法实现网络请求
class Observable{
public final void subscribe(Observer super T> observer) {
subscribeActual(observer);
}
}
final class CallExecuteObservable
@Override protected void subscribeActual(Observer super Response
Call
Response
if (!call.isCanceled()) {//传递给onNext方法
observer.onNext(response);
}
if (!call.isCanceled()) {
terminated = true;
observer.onComplete();
}
}
}
4. GsonConverterFactory:网络请求返回结果的处理
在OkHttpCall发起网络请求后,会调用parseResponse方法解析返回结果,然后通过结果转换器进行转换,默认转换器是BuiltInConverters,如果配置了GsonConverterFactory,则支持转换成我们自定义对象,实现类是GsonResponseBodyConverter
class OkHttpCall{
@Override
public Response
okhttp3.Call call;
call = getRawCall();
...
return parseResponse(call.execute());
}
Response
ResponseBody rawBody = rawResponse.body();
...
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try {
//调用结果转换器进行转换,这里会根据声明方法返回值类型选择不同转换器,比如返回默认的ResponseBody,则使用自带的BuiltInConverters转换,返回自定义对象则会使用GsonResponseBodyConverter进行转换
T body = responseConverter.convert(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
// If the underlying source threw an exception, propagate that rather than indicating it was
// a runtime exception.
catchingBody.throwIfCaught();
throw e;
}
}
}
Retrofit自带的默认转换器BuiltInConverters,支持处理返回类型是ResponseBody/Void 或者kotlin的Unit
final class BuiltInConverters extends Converter.Factory {
/** Not volatile because we don't mind multiple threads discovering this. */
private boolean checkForKotlinUnit = true;
@Override
public @Nullable Converter
Type type, Annotation[] annotations, Retrofit retrofit) {
if (type == ResponseBody.class) {
return Utils.isAnnotationPresent(annotations, Streaming.class)
? StreamingResponseBodyConverter.INSTANCE
: BufferingResponseBodyConverter.INSTANCE;
}
if (type == Void.class) {
return VoidResponseBodyConverter.INSTANCE;
}
if (checkForKotlinUnit) {
try {
if (type == Unit.class) {
return UnitResponseBodyConverter.INSTANCE;
}
} catch (NoClassDefFoundError ignored) {
checkForKotlinUnit = false;
}
}
return null;
}
}
Gson转换器GsonResponseBodyConverter,支持自定义对象类型的转换
final class GsonResponseBodyConverter
private final Gson gson;
private final TypeAdapter
GsonResponseBodyConverter(Gson gson, TypeAdapter
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();
}
}
}
5. 对kotlin协程的支持
判断是否kotlin suspend方法,在kotlin中suspend修饰的方法在编译成字节码并反编译成java代码后会发现方法参数里最后会多一个Continuation类型的参数,用于对协程的支持
kotlin字节码反编译后的java代码
public interface IUserServer {
... ...
@GET("banner/json")
@Nullable
Object getUserInfoBySuspend2(@Query("userId") @NotNull String var1, @NotNull Continuation var2);
}
Retrofit在RequestFactory解析方法参数时做判断
class RequestFactory{
class Builder{
boolean isKotlinSuspendFunction;
private @Nullable ParameterHandler> parseParameter(
int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
try {
if (Utils.getRawType(parameterType) == Continuation.class) {//判断是否suspend协程方法
isKotlinSuspendFunction = true;
return null;
}
} catch (NoClassDefFoundError ignored) {
}
}
}
}
根据方法返回类型,返回不同的HttpServiceMethod,当suspend方法直接返回自定义数据类型时(比如 UserData),返回的是SuspendForBody对象; 如果方法返回的是Response,则返回SuspendForResponse对象,这两个返回对象其实差不多,只是返回类型不一样
class HttpServiceMethod{
static
Retrofit retrofit, Method method, RequestFactory requestFactory) {
boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
boolean continuationWantsResponse = false;
if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
// Unwrap the actual body type from Response
responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
continuationWantsResponse = true;
}
if (continuationWantsResponse) {
//返回Response
return (HttpServiceMethod
new SuspendForResponse<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter
} else {
//返回UserData类型结果
return (HttpServiceMethod
new SuspendForBody<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter
continuationBodyNullable);
}
}
}
继续以SuspendForBody分析,在adapt方法被调用时,Retrofit会调用kotlin的扩展方法await/awaitNullable
static final class SuspendForBody
private final CallAdapter
private final boolean isNullable;
@Override
protected Object adapt(Call
call = callAdapter.adapt(call);//这里是默认的DefaultCallAdapterFactorys产生的Adapter
//获取suspend最后一个参数用于协程
Continuation
try {//调用Retrofit使用kotlin对Call类的扩展方法
return isNullable //返回的对象是否可为空
? KotlinExtensions.awaitNullable(call, continuation)
: KotlinExtensions.await(call, continuation);
} catch (Exception e) {
return KotlinExtensions.suspendAndThrow(e, continuation);
}
}
}
kotlin对Call方法扩展解析,协程方法中会异步发起网络请求并返回结果,当结束后会恢复到父协程地方继续执行
//这里是suspend方法,执行时协程会挂起
suspend fun
return suspendCancellableCoroutine { continuation ->
continuation.invokeOnCancellation {
cancel()//设置协程取消时的回调,调用Call的cancel方法
}
enqueue(object : Callback
override fun onResponse(call: Call
if (response.isSuccessful) {
val body = response.body()
if (body == null) {
val invocation = call.request().tag(Invocation::class.java)!!
val method = invocation.method()
val e = KotlinNullPointerException("Response from " +
method.declaringClass.name +
'.' +
method.name +
" was null but response body type was declared as non-null")
continuation.resumeWithException(e)//恢复协程并抛出异常
} else {
continuation.resume(body)//恢复协程并返回结果
}
} else {//恢复协程并抛出异常
continuation.resumeWithException(HttpException(response))
}
}
override fun onFailure(call: Call
continuation.resumeWithException(t)//恢复协程并抛出异常
}
})
}
}
小结
Retrofit实现原理: 答:Retrofit通过Create方法创建我们自定义接口实例时,会为我们接口创建一个动态代理;当调用接口方法的时候,会先根据配置的注解解析这个方法的信息,包括请求路径、请求参数、返回值等等,并把解析后的信息封装成对象并缓存起来; 然后根据方法的信息封装成一个Call对象,这个Call对象的默认实现类是OkHttpCall,内部是通过Okhttp发起同步或者异步网络请求; 然后调用Call的execute同步或者enqueue异步方法进行网络请求,返回结果后,会调用转换器对结果进行转换,默认是返回ResponseBody,也可以通过配置Gson转换器转成我们自定义类型; 如果需要对RxJava支持,返回Observer对象,则是需要配置一个Rxjava的CallAdapter,在适配器中将Call对象封装到Observer对象中并返回,当Observer的subscribe方法调用时会触发Call的网络请求操作,最后通过RxJava对结果分发; 如果需要对kotlin协程支持,Retrofit在对方法解析时会判断是否suspend方法,如果是的话,会执行Call的kotlin扩展方法,扩展方法也是suspend类型,在扩展方法中会挂起协程,通过Call对象执行网络请求操作,最后通过Continuation.resume方法恢复协程到父协程调用的地方 静态代理和动态代理的区别? 答:静态代理是指在代码编写的时候,代理类和被代理类的关系就确定了,编译后也会生成代理类字节码文件;而动态代理是指在运行时期,动态的通过反射方式为被代理的接口生成一个代理类,当调用这个接口的方法时,都会进入InvokeHandler的invoke方法中,从而实现对这个被代理接口的统一处理; 静态代理适合被代理的类比较少的情况,如果代理的类比较多,而且不需要做统一处理,则动态代理方便很多 Retrofit返回结果是如何切换到主线程的? 答:Retrofit会通过系统属性来判断是否Android平台,如果是Android平台,则会创建一个执行器,内部会创建一个主线程Looper的Handler,当网络请求结束返回结果时,会封装一个Runnable通过这个主线程Handler去执行,从而切换到主线程; 或者通过RxJava或者协程进行线程切换 对Kotlin协程(suspend方法)的支持
判断协程方法条件:判断方法最后一个参数是否是Continuation.class类型Retrofit使用kotlin对Call类扩展了suspend方法,在suspend方法中执行Call的网络请求,然后通过Continuation的resume方法恢复协程挂起并返回结果什么时候切回主线程的?在协程中调用continuation.resume方法后会自动回到它父协程所在线程,也就是主线程继续执行
参考阅读
发表评论