Retrofit源码全方面解析

如今作为一个Android开发者,网络请求这块离不开square公司的全家桶,今天我们就来分析一下其中的Retrofit框架的源码。(源码版本2.8.1)

为什么使用Retrofit

因为方便、直观,和OkHttp的结合天衣无缝:

@GET("weather")
fun weather(@Query("latitude") latitude: String, @Query("longitude") longitude: String): Flowable<String>

通过注解,对于这样的一个GET请求,请求参数以及返回结果,一目了然。并且还提供了多种CallAdapter以及Convert:
Retrofit源码全方面解析_第1张图片

  • RxJava2CallAdapterFactory:使得Retrofit可以RxJava结合使用

  • ObserveOnMainCallAdapterFactory: 根据官方demo自定义的CallAdapterFactory,这样就使得当Retrofit和RxJava结合使用时,我们不用每次对请求方法调用时添加如下代码:

    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    

Retrofit源码全方面解析_第2张图片

  • GsonConverterFactory:Gson和Retrofit结合使用,使得Body提交以及Response解析时面向对象编程

  • ScalarsConverterFactory:当提交的Body或者Response是如下类型时:

Retrofit源码全方面解析_第3张图片

我们可以使用该转换工厂,因为如果使用Gson转换工厂时,会抛异常:

Expected a string but was BEGIN_OBJECT at line 1 column 2 path $

这是使用String类型时的异常信息。

并且,Retrofit2.6之后,从框架内部提供了对Kotlin协程的支持,使得我们可以使用协程特性。

最后提一嘴,Retrofit的这种形式同SpringMVC中的声明方式及其类似。

Retrofit源码全方面解析_第4张图片

Retrofit.Builder类

对于Retrofit类的成员初始化,使用了建造者模式。

Retrofit源码全方面解析_第5张图片

Builder类的三个构造器。我们再看Builder.build()方法:

Retrofit源码全方面解析_第6张图片

  • 第一个红框:如果我们没有提供OkHttpClient对象,那么框架内部会为我们创建一个OkHttpClient对象。

  • 第二个红框:这里的callbackExecutor,实际上是为了最后请求结果的回调服务的,将执行流程从子线程切换到主线程。

Retrofit源码全方面解析_第7张图片

通过Handler,将执行流程切换到主线程

  • 第三个红框:将我们通过Retrofit.Builder配置的CallAdapterFactory放置到Retrofit对象中,并且添加一个默认的CallAdapterFactory

Retrofit源码全方面解析_第8张图片

至于这个DefaultCallAdapterFactory里面的逻辑我们放到后面去分析。

  • 第四个红框:将我们通过Retrofit.Builder配置的ConvertFactory放置到Retrofit对象中,并且前后各放入了ConvertFactory。

最后,创建Retrofit对象并返回。

Retrofit.create()方法出发

Retrofit源码全方面解析_第9张图片

这里只需要注意两个地方:

  • validateServiceInterface()方法,这个方法会来解析对应的接口方法的注解信息等
  • 通过Proxy.newProxyInstance(),返回了一个动态代理对象,供后续的接口请求使用

Retrofit.validateServiceInterface()方法

Retrofit源码全方面解析_第10张图片

  • 第一个红框:因为动态代理的限制,动态代理类实际上是抽象类Proxy的子类,由于Java是单继承的,所以用于动态代理的必须是接口
  • 第二个红框:根据传入的接口的Class对象,查找其父接口的信息,并且对于接口泛型进行了检查(不支持)
  • 第三个红框:对于定义在service接口中的一个个请求方法进行解析。

那么接下来的重点就是来看loadServiceMethod()方法的实现。

Retrofit.loadServiceMethod()

Retrofit源码全方面解析_第11张图片

Retrofit源码全方面解析_第12张图片

这块的逻辑很简单,通过一个map做存储Method对象到ServiceMethod的映射关系。已经在ServiceMethodCache中存在的,直接返回对应的ServiceMethod,因为解析请求方法注解的过程设计到大量的反射操作(后面会看到),这样就可以实现无论请求方法调用多少次,而解析的过程只有一次。

ServiceMethod.parseAnnotations()

Retrofit源码全方面解析_第13张图片

RequestFactory.parseAnnotations()

在这里插入图片描述
Retrofit源码全方面解析_第14张图片

我们只需要理解这两个方法即可

  • RequestFactory.Builder.parseMethodAnnotation():主要是对于方法注解的解析,例如@Header、@GET、@POST等

Retrofit源码全方面解析_第15张图片
Retrofit源码全方面解析_第16张图片

  • RequestFactory.Builder.parseParameter():对于参数注解的解析

Retrofit源码全方面解析_第17张图片

​ 这里只需要注意两个地方:先说第二个红框,这个地方是Retrofit对于Kotlin协程方法的支持,在笔者之前的文章中以及介绍过;第一个红框,这个parseParameterAnnotation()方法实现的代码很长,我们现在重点关注这一段:

Retrofit源码全方面解析_第18张图片
这段是对于@Body注解的解析。

在这里插入图片描述
Retrofit源码全方面解析_第19张图片

可以看到,这里会用上之前给Retrofit对象配置的ConverterFactory
Retrofit源码全方面解析_第20张图片

假定我们这里添加了两个ConverterFactory:ScalarsConverterFactory以及GsonConverterFactory。还记得在之前提到BuiltInConverters以及defaultConvert

Retrofit源码全方面解析_第21张图片

换句话说,convertFactories现在内部的结构如下:

Retrofit源码全方面解析_第22张图片

Retrofit源码全方面解析_第23张图片

由于传入的skipPast为null,所以start为0。最终使用谁,取决于factory.requestBodyConverter()方法的返回值是否为null。

  • BuiltInCoverts:此时返回null

Retrofit源码全方面解析_第24张图片

  • ScalarsConverterFactory:只要不是基本数据类型和String类型,返回null

Retrofit源码全方面解析_第25张图片

  • GsonConverterFactory:它就不返回null了。

Retrofit源码全方面解析_第26张图片

那么流程最多到这,就会找到对应的converter。

从这里也可以看出,一旦我们同时添加ScalarsConverterFactory和GsonConverterFactory,那么ScalarsConverterFactory在配置时一定要先与GsonConverterFactory添加

HttpServiceMethod.parseAnnotations()

通过ServiceMethod.parseAnnotations()的处理,将请求端相关信息已经解析完毕了,我们下面要分析的方法就是对响应端信息的解析。

Retrofit源码全方面解析_第27张图片

  • 第一个红框:这里我们就会用到前面为Retrofit配置的CallAdapterFactory。

Retrofit源码全方面解析_第28张图片
在这里插入图片描述

Retrofit源码全方面解析_第29张图片

看到这,发现和ConverterFactory是同样的套路。我们前面配置过两个Factory:RxJava2CallAdapterFactory和ObserveOnMainCallAdapterFactory,所以callAdapterFactories的结构如下:

Retrofit源码全方面解析_第30张图片

由于我们想分析支持Kotlin协程的逻辑,这俩就不看了(使用协程这俩就不用添加了),如果项目中使用到RxJava的同学可以自行深入分析一下。这样,这里返回的就是DefaultCallAdapterFactory。

  • 第二个红框:我们这里以支持Kotlin的suspend function为例,并且返回值类型不为Response类型,那么就会走到else分支里,将SuspendForBody对象返回回去。

Retrofit源码全方面解析_第31张图片

这是SuspendForBody的类层级关系:

在这里插入图片描述

至此,对于请求方法的解析已经完毕,都存放到SuspendForBody中,接下来我们就可以从实际发起网络请求开始继续往下分析。

动态代理的InvocationHandler

Retrofit源码全方面解析_第32张图片

对于在Object中定义的方法,不做特殊处理;然后通过loadServiceMethod()方法找到Method对象对应的ServiceMethod对象,调用其invoke()方法。在前面的基础上,我们知道此时的ServiceMethod对象实际上是SuspendForBody对象,SuspendForBody类的层级关系我们已经知道,所以执行流程会走到HttpServiceMethod的invoke()方法里:

在这里插入图片描述

Retrofit源码全方面解析_第33张图片

callAdapter基于前面的分析,这里是DefaultCallAdapterFactory的get()方法返回的:

Retrofit源码全方面解析_第34张图片

此时我们需要回头看一下Retrofit.Builder.build()方法:

Retrofit源码全方面解析_第35张图片

如果我们为其配置callbackExecutor,那么
Retrofit源码全方面解析_第36张图片

那么实际上意味着通过DefaultConverter的转换,变成了

Retrofit源码全方面解析_第37张图片

最后会走到KotlinExtensions.await()中:

Retrofit源码全方面解析_第38张图片

await()是Call的一个扩展方法,那么这里就会涉及到在Java中调用Kotlin扩展方法的知识,可参考笔者的另一篇文章。

此时,执行流程就会走到ExecutorCallbackCall的enqueue()方法:

Retrofit源码全方面解析_第39张图片

这里的delegate就是OkHttpCall,大家可以往前追溯一下。

此时,执行流程就会走到OkHttpCall的enqueue()方法:

Retrofit源码全方面解析_第40张图片

  • 第一个红框:会在这创建OkHttp框架中Call

Retrofit源码全方面解析_第41张图片

通过这个Call,调用异步请求enqueue()方法,通过OkHttp发起网络请求。

  • 第二个红框:解析OkHttp请求返回的Response

Retrofit源码全方面解析_第42张图片

到这里,就再次与ConverterFactory扯上关系。比如GsonConverterFactory里:

Retrofit源码全方面解析_第43张图片

Retrofit源码全方面解析_第44张图片

Retrofit源码全方面解析_第45张图片

这样,就通过Gson将JSON串转换成Java对象返回。

  • 第三个红框:通过回调,将执行逻辑回调回下面的代码

Retrofit源码全方面解析_第46张图片
Retrofit源码全方面解析_第47张图片

这样,就确保将执行流程返回到主线程,并且继续回调:

Retrofit源码全方面解析_第48张图片

在成功的情况下,通过resume()方法将执行权交还给挂起点:
在这里插入图片描述

这里只走了一遍成功的情况,失败的情况也可按照此方法分析,在这里就不再赘述了。

总结

至此,我们Retrofit源码的分析也告一段落了。Retrofit框架的源码十分优秀,类的结构设计非常清晰,运用了大量的设计模式,如门面模式、代理模式、建造者模式等。了解了内部代码结构可以指导我们在使用时遇到的问题,如同时使用ScalarsConverterFactory和GsonConverterFactory时要注意配置的顺序,更多的是学习代码设计思想,运用到日常开发中去,使得我们的代码耦合性低,易扩展。

你可能感兴趣的:(Android,android,java,kotlin)