您的位置:首页 > 理论基础 > 计算机网络

【源码解读】Retrofit网络请求过程源码解析

2016-09-22 09:13 681 查看
之前写了一个Gank.io的客户端练手学习了下RxJava+Retrofit的基本使用,顺着代码看了下相关的源码,将分析笔记记录于此,欢迎有兴趣的小伙伴多多指正,共同进步。

在写Gank的过程中,查看妹子福利时的代码如下,从创建接口到访问网络数据再到转换数据,RxJava+Retrofit到底是怎么完成的呢?

public interface GankApi {
@GET("data/福利/{number}/{page}")
Observable<GankGirlResult> getGirls(@Path("number") int number, @Path("page") int page);
}
//1.创建Retrofit对象
Retrofit retrofit = new Retrofit.Builder()
.client(okHttpClient)
.baseUrl(baseUrl)
.addConverterFactory(gsonConverterFactory)
.addCallAdapterFactory(rxJavaCallAdapterFactory)//4
.build();//5
//2.构造请求接口
gankApi = retrofit.create(GankApi.class);
//3.执行请求
gankApi.getGirls(10, page++)


按照代码我们的分析也分成了三块:Retrofit对象的创建、GankApi请求接口的生成、执行网络请求的调用。

一、Retrofit对象的创建

Retrofit采用Builder模式创建,首先从Builder开始看起,先是初始化平台对象,并向集合converterFactories中默认添加了一个BuiltInConverters对象

Builder(Platform platform) {
this.platform = platform;
// 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());
}


1.client(okHttpClient)与baseUrl(baseUrl)

我们知道Retrofit本质上还是利用OkHttp进行网络访问,这一步就是提供一个okHttpClient对象用来发送请求,同时设置请求地址的基本路径。如果不设置则会报异常。

2.addConverterFactory与addCallAdapterFactory

这一步指定使用Gson对返回数据进行解析,使用RxJava进行回调,具体创建操作后面再进行分析。

public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}

public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
adapterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}


3.build()

这里就是基于Builder创建Retrofit的代码,主要信息都在注释里面了。

public Retrofit build() {

//1.如果没有设置baseUrl则抛出异常
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
//2.如果没有设置OkHttpClient对象则进行设置
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
//3.如果没有设置Executor则根据平台设置默认的Executor
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}

//4.基于Executor创建默认的CallAdapter.Factory,这里具体就是ExecutorCallAdapterFactory对象
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
callbackExecutor, validateEagerly);
}


上面就是其Retrofit的对象的构建过程,基本就是设置了OkHttpClient和基础路径,然后设置Converter.Factory和CallAdapter.Factory。有一点区别是Converter.Factory的集合在我们设置GsonConvert之前就添加了一个元素BuiltInConverters,而对于CallAdapter.Factory则是在设置完成后添加的。对于构建完成后的两个集合如下(偷懒直接断点截了个图,捂脸):



下面是我们关注的重点,其create方法创建我们想要的Api类以及方法的调用

二、请求接口的生成

通过下面的create方法的代码我们可以看出Retrofit是通过动态代理来创建调用我们的请求方法的,首先将调用的Method解析为ServiceMethod,

然后封装为OkHttpCall请求对象,最后通过CallAdapter执行请求返回数据。这一部分我们重点分析ServiceMethod的创建。

public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();

@Override public Object invoke(Object proxy, Method method, Object... args)
throws Throwable {
//...代码省略

//1.将Method解析为ServiceMethod对象
ServiceMethod serviceMethod = loadServiceMethod(method);
//2.将ServiceMethod和args参数封装为OkHttpCall对象
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
//3.发送请求返回封装好的Call对象,如果是RxJava作为Adapter则返回Observable对象
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}


1.将Method封装为ServiceMethod对象

public Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;、
this.method = method;
this.methodAnnotations = method.getAnnotations();//获取方法的注解数组
this.parameterTypes = method.getGenericParameterTypes();//获取形参数据
this.parameterAnnotationsArray = method.getParameterAnnotations();//获取形参的注解
}

public ServiceMethod build() {
//1.创建CallAdapter对象,并获取响应的数据类型,其实我们要转换的数据类型
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
//2.创建Converter对象
responseConverter = createResponseConverter();
//3.解析方法注解
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
//4.解析参数注解
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
return new ServiceMethod<>(this);
}


上面是去掉各种异常处理之后的简化代码,其主要做了四项操作。

下面来看下四步的代码(具体到细节的话每一步都可以写成一篇文章,因此这里只做简单分析):

CallAdapter的创建

最终调用的是Retrofit中的nextCallAdapter。

上面提到了,在构建Retrofit时,使用List集合存放CallAdapter.Factory,RxJavaCallAdapterFactory存放于0,默认的DefaultCallAdapterFactory或者ExecutorCallAdapterFactory存放于1,因此在创建CallAdapter时如果设置了RxJavaCallAdapterFactory优先使用RxJavaCallAdapterFactory创建Adapter。

//adapterFactories集合,默认skipPast为null,因此indexOf返回-1,start从0开始,遍历第一个就是RxJavaCallAdapterFactory
//使用该对象创建CallAdapter对象,
public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
checkNotNull(returnType, "returnType == null");
checkNotNull(annotations, "annotations == null");

int start = adapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = adapterFactories.size(); i < count; i++) {
CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
}


下面是RxJavaCallAdapterFactory的get方法具体的代码,returnType参数就是我们所调用方法的返回值类型

@Override
public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
Class<?> rawType = getRawType(returnType);
//获取全类名为rx.Observable因此isSingle与isCompletable均为false,最终调用getCallAdapter方法来获取对象
//具体细节这里不再分析,这里最终返回的是SimpleCallAdapter类的对象。
String canonicalName = rawType.getCanonicalName();
boolean isSingle = "rx.Single".equals(canonicalName);
boolean isCompletable = "rx.Completable".equals(canonicalName);
if (rawType != Observable.class && !isSingle && !isCompletable) {
return null;
}

if (isCompletable) {
return CompletableHelper.createCallAdapter(scheduler);
}

CallAdapter<Observable<?>> callAdapter = getCallAdapter(returnType, scheduler);
if (isSingle) {
return SingleHelper.makeSingle(callAdapter);
}
return callAdapter;
}


PS:RxJavaCallAdapterFactory提供了ResponseCallAdapter、SimpleCallAdapter、ResultCallAdapter三种Adapter,具体细节区别有兴趣的同学可以研究下源码。

Converter的创建

和存储RxJavaCallAdapterFactory的集合相反,存储Converter对象的集合第一个存储的是BuiltInConverters对象,其次存储的是我们的GsonConverterFactory,最终调用的是Retrofit中的nextResponseBodyConverter方法

其创建方法如下:

public <T> Converter<ResponseBody, T> nextResponseBodyConverter(Converter.Factory skipPast,
Type type, Annotation[] annotations) {
checkNotNull(type, "type == null");
checkNotNull(annotations, "annotations == null");
//start为0
int start = converterFactories.indexOf(skipPast) + 1;

for (int i = start, count = converterFactories.size(); i < count; i++) {
//首先遍历到的是BuiltInConverters,这时的返回类型就是我们定义方法里面的类型,BuiltInConverters的responseBodyConverter返回null。第二次遍历是GsonConverterFactory的GsonResponseBodyConverter,直接返回GsonResponseBodyConverter对象,
Converter<ResponseBody, ?> converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
if (converter != null) {
//noinspection unchecked
return (Converter<ResponseBody, T>) converter;
}
}

}
//创建GsonResponseBodyConverter
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonResponseBodyConverter<>(gson, adapter);
}


解析方法注解和参数注解

解析方法注解,下面是我摘取的部分方法代码,可以看到我们很熟悉的GET和POST请求注解的解析,也包括http和head的解析。我们创建网络接口上的注解就是在这里进行解析的。

private void parseMethodAnnotation(Annotation annotation) {

if (annotation instanceof GET) {
parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
} else if (annotation instanceof HEAD) {
parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
if (!Void.class.equals(responseType)) {
throw methodError("HEAD method must use Void as response type.");
}
}  else if (annotation instanceof POST) {
parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
} else if (annotation instanceof PUT) {
parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
} else if (annotation instanceof OPTIONS) {
parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
} else if (annotation instanceof HTTP) {
HTTP http = (HTTP) annotation;
parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
}
}


对于参数注解的解析,首先遍历每一个参数的每一个注解,然后对每个参数的注解构造ParameterHandler对象。具体细节这里不再赘述

上述操作完成后就完成了ServiceMethod的构建。

三、执行请求

在构建请求完成后就是调用我们的方法了,具体到我们的代码就是调用了SimpleCallAdapter的adapt方法:

@Override public <R> Observable<R> adapt(Call<R> call) {
Observable<R> observable = Observable.create(new CallOnSubscribe<>(call)) //1.将call传递给CallOnSubscribe,执行网络请求
.flatMap(new Func1<Response<R>, Observable<R>>() {//2.对数据进行转换成函数所需要的Obserable对象,
@Override public Observable<R> call(Response<R> response) {
if (response.isSuccessful()) {
return Observable.just(response.body());
}
return Observable.error(new HttpException(response));
}
});
//
if (scheduler != null) {
return observable.subscribeOn(scheduler);
}
return observable;


可以看到,首先是将call传递给了CallOnSubscribe。这是RxJavaCallAdapterFactory的一个内部类,简化后的代码如下

static final class CallOnSubscribe<T> implements Observable.OnSubscribe<Response<T>> {
private final Call<T> originalCall;

CallOnSubscribe(Call<T> originalCall) {
this.originalCall = originalCall;
}

@Override public void call(final Subscriber<? super Response<T>> subscriber) {
// Since Call is a one-shot type, clone it for each new subscriber.
final Call<T> call = originalCall.clone();

// Attempt to cancel the call if it is still in-flight on unsubscription.
subscriber.add(Subscriptions.create(new Action0() {
@Override public void call() {
call.cancel();
}
}));
//执行网络请求
Response<T> response = call.execute();
if (!subscriber.isUnsubscribed()) {
subscriber.onNext(response);
}
}
}


可以看到是在CallOnSubscribe的call方法中执行了网络请求execute()并将Response对象作为参数通过flatMap转换为相应的Observable对象,也就是我们的接口方法的返回类型Observable,剩下的就是利用Gson和RxJava进行数据的解析和转换最终生成符合我们需要的数据。

到这里我们开头访问妹子福利代码的执行流程基本搞清楚了,总体而言Retrofit源码比较简单而且设计的非常好,建议大家都去认真阅读下。

最后总结下阅读源码的三点感受:

1. 不要只看分析文章,自己分析源码很重要

2. 结合代码,从一个点开始顺藤摸瓜,总会找到让你高潮的代码与逻辑

3. 断点调试很重要!断点调试很重要!断点调试很重要!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: