一、前言
之前看了okhttp的源码,然后我们的项目中一般都是okhttp + retrofit组合的形式,所以也想看一下retrofit的源码,看看它是如何通过注解与okhttp组合进行网络请求的。本文只是记录一下自己的学习过程,理解一下retrofit的执行流程,将整个网络请求过程打通。
二、源码流程讲解
说明:代码讲解主要围绕使用的流程来讲解
2.1、retrofit的调用方式
Retrofit rxRetrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create()) //添加一个转换器,将gson数据转换为bean类
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()) //配合Rxjava使用的时候添加的回调适配器
.client(okHttpClient) //添加okhttpClient
.build();
ixxxServer = rxRetrofit.create(IXXXServer.class);
2.1.1 Retrofit.Builder()
说明:该方法主要是进行Retrofit使用平台的初始化,retrofit支持Android和Java8两个平台,代码如下:
public Builder() {
this(Platform.get());
}
//Platform.java
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
return new Android(); //Android平台
}
} catch (ClassNotFoundException ignored) {
}
try {
Class.forName("java.util.Optional");
return new Java8(); //java8平台
} catch (ClassNotFoundException ignored) {
}
return new Platform();
}
2.1.2 baseUrl(baseUrl)
说明:传入baseUrl,如:http://www.baidu.com/, 该方法主要是传值,并校验该值是否为空
2.1.3 addConverterFactory(XXX) addCallAdapterFactory(XXX) build()
说明:这两个方法在retrofit的逻辑基本上是一致的,都是分别有一个list存储转换器和适配器,并都有一个默认的值,代码如下:
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) { //如果callFactory为空时,创建一个OkHttpClient
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor(); //创建一个默认的callbackExecutor
}
// callAdapterFactories 为存储适配器的集合
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
//platform.defaultCallAdapterFactories(callbackExecutor) 为默认的适配器
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
List<Converter.Factory> converterFactories = new ArrayList<>(
1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
// ensures correct behavior when using converters that consume all types.
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(platform.defaultConverterFactories());
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
最终,这两个集合传入Retrofit的构造函数中,作为参数一遍后面的逻辑使用。那么问题来了,这个集合存储了好几个适配器,那他们是如何定位到我们所需要的那个适配器呢?答案是,根据我们 请求网络的方法的返回值进行匹配,后面会讲到。
2.1.4 client(okHttpClient)
说明:传入okhttpClient值,retrofit内部将该值存储为callFactory,该值,作为retrofit链接okhttp的桥梁。
2.2 ixxxServer = rxRetrofit.create(IXXXServer.class)
说明:该方法为Retrofit的核心入口,前面那些调用,仅是一些基本的赋值操作,而该方法则是处理retrofit用到的注解、返回值等必要因素,并利用代理的方式生成IXXXServer的代理,然后我们就可以用生成的代理直接调用方法。代码如下:
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();
private final Object[] emptyArgs = new Object[0];
@Override public 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);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
说明:上面newProxyInstance()这个方法有三个参数,第一个是类加载器,第二个是一个Interface对象的数组,即我们需要代理的Interface,这里我们是IXXXServer,第三个为一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上,我们主要看的是InvocationHandler的invoke()这个方法,该方法也有三个参数:
- proxy 动态代理,指代我们所要代理的那个真实的对象,如 IXXXService.java这个类
- method 真实代理类中的方法,如:IXXXService类中的 getData(33,89)
- args 方法中接收的参数,如上面的getData的(33,89)
在inivoke()方法中,重点在于 loadServiceMethod(method).invoke(args != null ? args : emptyArgs);,这行代码,我们拆分为两部分,首先是,然后是invoke(args != null ? args : emptyArgs)
2.2.1 loadServiceMethod(method)
代码如下:
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;
}
说明:上面有一个serviceMethodCache字段,为一个Map集合Map<Method, ServiceMethod<?>>,方法为key,ServiceMethod为value,其中ServiceMethod是处理IXXXService方法中的注解、返回值对象,类型等的类的一个入口类(真正处理的是在RequestFactory),我们重点看下 result = ServiceMethod.parseAnnotations(this, method)这一行代码,实现是在SerViceMethod.java中:
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
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.parseAnnotations(retrofit, method)这个方法,点进去到RequestFactory这个类中,看到该方法实际执行了一个new Builder(retrofit, method).build()方法,首先看下前面那部分,new Builder(retrofit, method)。代码如下:
前置:
@GET("/api/user-purchased/v1")
fun getHavePurchasedList(@Query("page") page: Int?,
@Query("limit") limit: Int?): Observable<V2ResponseModel<List<HavePurchasedRawDataModel>>>
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit; //前面传进来的retrofit
this.method = method; //我们所要调用的方法
this.methodAnnotations = method.getAnnotations(); //获得方法的注解 如:@GET
this.parameterTypes = method.getGenericParameterTypes(); //获得方法中参数的类型 如:Int
this.parameterAnnotationsArray = method.getParameterAnnotations(); //获得方法中参数的注解 如:@Query
}
然后我们再看下build()这个方法:
{
for (Annotation annotation : methodAnnotations) { //遍历上面得到的方法注解
parseMethodAnnotation(annotation); //解析每个注解
}
......代码省略......
int parameterCount = parameterAnnotationsArray.length; //获得参数注解的个数
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
parameterHandlers[p] = parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p]); //解析参数注解
}
......代码省略......
return new RequestFactory(this);
}
说明:我们先看下parseMethodAnnotation(annotation)这个方法,如下:
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);
} 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());
} else if (annotation instanceof retrofit2.http.Headers) {
String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
if (headersToParse.length == 0) {
throw methodError(method, "@Headers annotation is empty.");
}
headers = parseHeaders(headersToParse);
} else if (annotation instanceof Multipart) {
if (isFormEncoded) {
throw methodError(method, "Only one encoding annotation is allowed.");
}
isMultipart = true;
} else if (annotation instanceof FormUrlEncoded) {
if (isMultipart) {
throw methodError(method, "Only one encoding annotation is allowed.");
}
isFormEncoded = true;
}
}
其中每个注解都会调用parseHttpMethodAndPath这方法,最后是得到@GET("/api/user-purchased/v1")里面的值/api/user-purchased/v1,用relativeUrlParamNames这个字段进行保存,我们重点看一下下面的几行代码:
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
parameterHandlers[p] = parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p]);
}
说明:该方法最终执行 parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p]),这个方法有三个参数,第一个为p,是参数注解的index,第二个是该index的参数类型,第三个是该index上参数的注解,我们继续点进去看一下:最终执行的是:
private ParameterHandler<?> parseParameterAnnotation(
int p, Type type, Annotation[] annotations, Annotation annotation) {
...... 代码省略......
if (annotation instanceof Path) { //解析Path
...... 代码省略.....
} else if (annotation instanceof Query) {
validateResolvableType(p, type);
Query query = (Query) annotation; //参数注解
String name = query.value(); //参数的值
boolean encoded = query.encoded(); //是否编码
Class<?> rawParameterType = Utils.getRawType(type); //返回承载该泛型信息的对象,如:List<String>中的List
gotQuery = true;
if (Iterable.class.isAssignableFrom(rawParameterType)) { //判断是否是集合
if (!(type instanceof ParameterizedType)) {
throw parameterError(method, p, rawParameterType.getSimpleName()
+ " must include generic type (e.g., "
+ rawParameterType.getSimpleName()
+ "<String>)");
}
ParameterizedType parameterizedType = (ParameterizedType) type;
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType); //用于获取泛型的参数 如:List<String> 中的String
//这个coverter将参数转成字符串,利用到了我们一开始传入的BuiltInConverters,后面有代码讲解
Converter<?, String> converter =
retrofit.stringConverter(iterableType, annotations);
//返回一个操作参数的句柄,在我们okhttpClient将会使用到,此处仅仅是数据存储
return new ParameterHandler.Query<>(name, converter, encoded).iterable();
} else if (rawParameterType.isArray()) { //判断是否是数组
Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
Converter<?, String> converter =
retrofit.stringConverter(arrayComponentType, annotations);
return new ParameterHandler.Query<>(name, converter, encoded).array();
} else { //参数非数组或者集合
Converter<?, String> converter =
retrofit.stringConverter(type, annotations);
return new ParameterHandler.Query<>(name, converter, encoded);
}
} else if (annotation instanceof QueryName) {
...... 代码省略......
} else if (annotation instanceof QueryMap) {
...... 代码省略......
return new ParameterHandler.QueryMap<>(valueConverter, ((QueryMap) annotation).encoded());
我们再看下上面说到的Converter<?, String> converter = retrofit.stringConverter(iterableType, annotations)这一行将参数转成字符串的代码
public <T> Converter<T, String> stringConverter(Type type, Annotation[] annotations) {
checkNotNull(type, "type == null");
checkNotNull(annotations, "annotations == null");
......代码省略......
return (Converter<T, String>) BuiltInConverters.ToStringConverter.INSTANCE; //初始化一个ToStringConverter
}
至此,我们的ServiceMethod的解析参数的RequestFactory.parseAnnotations(retrofit, method)流程已经说完,返回RequestFactory对象,我们再看ServiceMethod类中的parseAnnotations方法的最后一行代码
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);//解析的注解返回RequestFactory的对象
......代码省略......
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory); //在HttpServiceMethod类中解析注解
}
由此,我们进入HttpServiceMethod类中的parseAnnotations方法,代码如下:
//三个参数:retrofit,指代我们所创建的这个retrofit,method,我们所代理的方法,factory,上面返回得RequestFactory对象
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method); //获得一个CallAdapter,下面会讲
//获得我们服务器响应的返回值类型,例如Observable<V2ResponseModel<MarketStatusListModel>> 中的V2ResponseModel<MarketStatusListModel>
Type responseType = callAdapter.responseType();
......代码省略......
//获得响应数据的转换器,例如GsonConverterFactory
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory; // HttpCallFactory,这个callFactory字段很重要,将retrofit盘活了
return new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter);
}
下面我们看下上面说到的获取callAdapter的方法CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method),最后执行的方法如下:
参数说明:第一个参数,此参数始终为空null,第二个参数 方法的泛型返回值类型,第三个参数,方法的注解
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
......代码省略......
int start = callAdapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
......代码省略......
}
说明:该方法遍历我们callAdapterFactories所存储的callAdapter,我一开始讲解这个集合的时候有一个疑问,就是我们如何得到我们想要的那个或者说我们传入的那个callAdapter呢,答案就是在这里,get(returnType, annotations, this)这一行,根据我们的返回值类型及注解,来判断我们所要的那个callAdapter。至于如何得到该adapter,大家可以看RxJava2CallAdapterFactory这个类,我这里就不说了。
我们在我那个上一层看: return new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter)
此处返回一个HttpServiceMethod类,里面的参数我们拿到了我们解析方法参数的requestFactory,Okhttp 的callFactory,callAdapter以及数据转换的responseConverter,由此,retrofit数据请求的所有的前期准备已经完备了,类似于我们做一个电器,并让它能够运转,电器准备好了,接上电源就好了,我们电源也准备好了OKHTTP3,现在,我们只要一个接头,接入即可,那么这个接头是啥呢?我们一开始分析的Retrofit类中的create()方法中那个代理方法中的loadServiceMethod(method).invoke(args != null ? args : emptyArgs)方法的前半部分loadServiceMethod,我们还有invoke方法没有说明,那么这个invoke方法,就是我们刚才比喻的接头,下面我们上代码:
@Override ReturnT invoke(Object[] args) {
return callAdapter.adapt(
new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
}
说明:该方法是ServiceMethod这个类的抽象方法,其实现在HttpServiceMethod类中,我们看上面的代码只有一行,有几个关键的点,第一、callAdapter.adapt(),第二、OkHttpCall,我们分开讲。
callAdapter.adapt()
有人会问,这个callAdapter是什么,这个callAdapter是我们上面分析到的得到的那个callAdapter
return new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter);
看见第三个参数没,就是这个,例如加入我们传入的是RxJava2CallAdapterFactory,在该类中的get方法中有一行代码是创建RxJava2CallAdapter的代码,如:
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
Class<?> rawType = getRawType(returnType);
......代码省略......
return new RxJava2CallAdapter(responseType, scheduler, isAsync, isResult, isBody, isFlowable,
isSingle, isMaybe, false);
}
然后我们在看下adapt方法,由于我用的是RxJava2CallAdapterFactory,我就用RxJava2CallAdapter来讲解吧,代码如下:
//这个call为我们上面说到的OkHttpCall
@Override public Object adapt(Call<R> call) {
Observable<Response<R>> responseObservable = isAsync //isAsync 是否异步
? 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;
}
我这边就将异步执行吧,我们按照代码跳到CallEnqueueObservable这个类中,new CallEnqueueObservable<>(call) 这个方法只是进行赋值,真正关键在于subscribeActual这方法
@Override protected void subscribeActual(Observer<? super Response<T>> observer) {
// Since Call is a one-shot type, clone it for each new observer.
Call<T> call = originalCall.clone(); //originalCall为刚才传入的值
CallCallback<T> callback = new CallCallback<>(call, observer);
observer.onSubscribe(callback);
call.enqueue(callback); //这行是开始执行,这是重点
}
我们再看下OKHttpCall这个类中的enqueue方法
@Override public void enqueue(final Callback<T> callback) {
......代码省略......
if (call == null && failure == null) {
try {
call = rawCall = createRawCall(); //这行是重点,下面会讲
} catch (Throwable t) {
throwIfFatal(t);
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure); //失败回调
return;
}
if (canceled) {
call.cancel();
}
.....代码省略......
}
说明,我们这边看下call = rawCall = createRawCall()这个方法
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
说明:callFactory.newCall()方法执行的是okhttp3里面的方法,我们重点看下该方法传入的参数requestFactory.create(args),create()方法里面的args为我们请求网络时的参数,我们再看下requestFactory.create()这个方法
okhttp3.Request create(Object[] args) throws IOException {
@SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
//parameterHandlers字段为之前所说的解析方法注解之后返回的一个操作句柄
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
int argumentCount = args.length;
......代码省略......
//创建requestBuilder ,传入的参数包括请求方式,完整的请求Url等
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl,
headers, contentType, hasBody, isFormEncoded, isMultipart);
List<Object> argumentList = new ArrayList<>(argumentCount);
for (int p = 0; p < argumentCount; p++) {
argumentList.add(args[p]);
handlers[p].apply(requestBuilder, args[p]);
}
return requestBuilder.get()
.tag(Invocation.class, new Invocation(method, argumentList))
.build();
}
最后,我们就将retrofit与okhttp已经连接起来了。最后有一个问题就是返回的数据,是在哪里进行转成我们所需要要的model呢,我们回到OkHttpCall的enqueue方法,看到有一行是拿到上面返回的call,然后再执行enqueue方法
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
......代码省略......
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
response = parseResponse(rawResponse);//这里是解析响应数据,并返回我们所想要的那种数据类型
} catch (Throwable e) {
throwIfFatal(e);
callFailure(e);
return;
}
try {
callback.onResponse(OkHttpCall.this, response); //成功回调
} catch (Throwable t) {
t.printStackTrace();
}
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e); //失败回调
} catch (Throwable t) {
t.printStackTrace();
}
}
});
}
成功回调之后CallEnqueueObservable中的onResponse()方法得以执行,代码如下:
@Override public void onResponse(Call<T> call, Response<T> response) {
if (call.isCanceled()) return;
try {
observer.onNext(response);
if (!call.isCanceled()) {
terminated = true;
observer.onComplete();
}
} catch (Throwable t) {
if (terminated) {
RxJavaPlugins.onError(t);
} else if (!call.isCanceled()) {
try {
observer.onError(t);
} catch (Throwable inner) {
Exceptions.throwIfFatal(inner);
RxJavaPlugins.onError(new CompositeException(t, inner));
}
}
}
}
上面我们看到了Rxjava的熟悉的方法onNext()onComplete()方法,至此,我们在代码中便可收到响应的数据,一个完整的流程走完了。
三、总结
通过查看代码可知道,其实retrofit只是对okhttp的上层数据进行一次封装,让用户使用起来更加的方便,而真正的网络请求则是在OKHttp中,retrofit重要的两个点在于代理以及解析方法的注解。哈哈,说的好简单
四、写在最后
本人水平有限,看源码比较粗浅,只能对源码的大概流程了解,有一些地方还是有些不太明白,哈哈,有些地方就带过啦。写这个博文写了好多天,其实看明白与写出来还是有比较大的差距的,我也不想胡乱写,有些地方还是得查资料,所示花的时间比较长。有分析的不对的地方,欢迎大佬指正!