Retrofit原理与设计模式分析

Retrofit概要

  • Retrofit是一个网络请求框架的封装,把每一个http的api请求变成java接口,只是一个restful风格网络请求框架的封装,而不是网络请求框架,其主要工作都由其内核okhttp来完成。Retrofit主要完成数据的转化与适配。Retrofit设计模式使用了许多设计模式,所以具有很多的扩展性,能与Rxjava、json、okhttp等主流库进行无缝对接。

Retrofit设计模式

  • 构建者模式
  • 工厂方法
  • 外观模式
  • 策略模式
  • 适配器模式
  • 动态代理
  • 观察者模式

Retrofit快速使用

  • 定义网络请求接口
  • 定义接口方法
  • 构建Retrofit
  • 获取网路请求接口
  • 获取请求Call
  • 执行同/异步网络请求
public interface MyInterface  {

    @GET("www.baidu.com/{user}/first")
    Call getService(@Path("user")String  user);
    
    @GET(".../...")
    Call> getCall();
}
复制代码
//java
Retrofit retrofit=new Retrofit.Builder()
    .baseUrl("http://www.baidu.com")
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
    .addConverterFactory(GsonConverterFactory.create())
    .build();

MyInterface myInterface = retrofit.create(MyInterface.class);

retrofit2.Call call = iMyService.getService("lisi");

call.enqueue(new retrofit2.Callback() {
    @Override
    public void onResponse(retrofit2.Call call, retrofit2.Response response) {

    }

    @Override
    public void onFailure(retrofit2.Call call, Throwable t) {

    }
});
复制代码
//kotlin
var retrofit = Retrofit.Builder()
    .baseUrl("http://www.baidu.com")
    .addConverterFactory(GsonConverterFactory.create())
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
    .build()

var  myInterface = retrofit.create(MyInterface::class.java)

var call = myInterface.getCall()

call.execute()

call.enqueue(object : Callback<List<String>> {
    override fun onResponse(call: Call<List<String>>, response: Response<List<String>>) {

    }

    override fun onFailure(call: Call<List<String>>, t: Throwable) {

    }

})
复制代码

Retrofit原理分析

网络通信八大步骤

Retrofit.png

Retrofit类的构建

Retrofit类中七大成员变量

  • serviceMethodCache是Map类型数据key值Method是Http请求方法,value是ServiceMethod是解析网络请求接口后的对象,与注解中的GetPut是成对出现的,缓存网络请求信息的对象,用于缓存网络请求方法与配置、数据转换器、网络请求适配器等等
  • callFactory用于生产okhttpClient
  • baseUrl网络请求基地址与接口中的相对地址拼接起来就是完整的网络地址
  • converterFactories数据转换器工厂集合,数据转换就是把网路请求得Reponse转换成Java对象
  • callAdapterFactories网络请求适配器工厂集合,网络请求适配器就是把Call对象转换成其它类型。例如想执行Rxjava时候就转化成Rxjava得call对象
  • callbackExecutor 用于执行回调,处理异步网络请求
  • validateEagerly是一标志位,表示是否立即解析接口中方法

微信截图_20210802153358.png

Retrofit中Builder

  • 表示Retrofit的创建是构造者模式
  • 成员变量
    • platform表示Retrofit适配的平台,例如Android、java8、ios等
    • callFactory表示请求网络的okhttp工厂,默认情况下是okhttpClient
    • baseUrl网络请求url地址
    • converterFactories数据转换器工厂
    • callAdapterFactrories网络请求适配器集合
    • callbackExecutor用于执行异步回调,在Android中默认执行主线程Executor
    • validateEagerly标志位,表示是否立即解析接口中方法,在动态代理中会用到
  • 成员变量除了platformserviceMethodCache不同外,Retrofit.Builder成员变量与Retrofit大体相同

微信截图_20210802161526.png

  • Platform对象是一个单例,通过反射findPlatform()查找当加载指定类,返回Android对象表示使用Android平台

微信截图_20210802163454.png

    • Android对象中,defaultCallbackExecutor()方法返回一默认的回调方法执行器,用于从子线程切换到主线程,同时可以在主线程中执行回调方法
      • MainThreadExecutor类中new Handler(Looper.getMainLooper())也证明了与主线程进行绑定
    • 由于当前Android对象是继承Platform,因此默认网络请求适配器方法由于Platform中的defaultCallAdapterFactories方法获得

微信截图_20210802164143.png

  • 相对于无参构造,Builder的有参构造有两个,一个人是用于赋值给Builder中的platform,另一个在platform参数。另外一个在platform参数上的处理是一样的,其它主要参数使用传入retrofit的参数进行赋值

微信截图_20210802174747.png

  • 注意目前Builder的各参数只是默认值的初始化,并没有进行具体的配置,没有正在配置到Retrofit的成员变量中

Retrofit类中baseUrl()方法

  • 首先进行工具类判断传入参数是否为空
  • 然后将String类型的Url转为HttpUrl类型的Url

微信截图_20210802180256.png

  • 然后对路径列表pathSegments进行赋值,主要将Http的Url拆分成多个独立碎片
  • 判断http地址最后是否以斜杠结尾否则抛出异常
  • 最后对baseUrl进行赋值并返回当前Builder(便于后面链式调用)

微信截图_20210802180434.png

Retrofit类中addConverterFactory()方法

  • 这个方法主要把当前对象添加到converterFactories数据转换器工厂集合中

微信截图_20210802184411.png

  • GsonConverterFactory主要功能是运用工厂模式创建含有json对象的GsonConverterFactory

微信截图_20210802184619.png

Retrofit类中addCallAdapterFactory()方法

  • 这个方法主要把当前对象添加到callAdapterFactories网络请求适配器工厂集合中

微信截图_20210802191118.png

  • RxJava2CallAdapterFactory.create()作用是创建含有scheduler调度器的RxJava2CallAdapterFactory对象
  • 将Retrofit中的Call对象封装成java对象

微信截图_20210802191046.png

  • 这里先简要说明,在Rxjava2CallAdapter中的adapt方法中的observable.subscribeOn(scheduler)表示在订阅关系建立后进行了网络请求

Retrofit类中build()方法

  • 首先进行了baseUrl的非空判断
  • callFactory为空情况下,创建OkHttpClient()对象并赋值给callFactory
  • 初始化回调方法执行器callbackExecutor,在空的情况下会调用上面我们研究过的platform类中的platform.defaultCallbackExecutor()进行配置
  • 复制网络请求适配器工厂集合callAdapterFactories并添加平台默认callAdapter
  • 创建数据转换器工厂集合副本converterFactories并添加原来说有converterFactories、平台默认数据转换器、内置数据转换器工厂BuiltInConverters(Retrofit内部默认指定提供的)
  • 最后把以上成员变量传到new Retrofit()中进行对象创建

微信截图_20210802191626.png 微信截图_20210802191714.png

创建网络接口实例

代码流程

  • 在使用过程中,我们先定义接口
  • 这里主要的是@GET注解中可以是全路径,那么就可以不设置baseUrl()
interface MyInterface {

    @GET(".../...")
    Call<List<String>> getCall();
}
复制代码
  • 然后调用创建好的retrofit对象中的create()方法
  • 这里采用了外观模式与动态代理模式
var  myInterface = retrofit.create(MyInterface::class.java)
复制代码

retrofit.create()方法分析

  • 首先validateServiceInterface()是对我们传进来的字节码进行验证
  • 然后我们可以看到之前的标志位validateEagerly这理接下来的逻辑表示我们是否要提前验证接口,是否需要提前解析接口
    • 这里的实现为首先获取具体平台
    • 然后通过反射获取我们传递对象的方法
    • 遍历接口中的方法
    • 满足判断条件后调用loadServiceMethod(method)

微信截图_20210803112752.png

微信截图_20210803113728.png

      • loadServiceMethod()中有一个很重要的对象ServiceMethod,它是我们定义的接口方法Call通过动态代理封装转化而来的,一个ServiceMethod对应一个接口方法Call
      • 然后不会直接创建ServiceMethod,从缓存池中取,采用线程同步锁 来锁住serviceMethodCache
      • 如果通过serviceMethodCache.get(method)获取到的result不为空,则返回result。若result为空,则创建一个ServiceMethod(构建者模式),最后把创建好后result保存到serviceMethodCache
      • 最终会返回ServiceMethod对象

微信截图_20210803114019.png

  • 回过头来看create方法,从Proxy.newProxyInstance可以看出,该方法return是一个网路请求接口的动态代理对象
  • 对于Proxy.newProxyInstance这个方法,我们会传进来一个Class对象(new Class<?>[] {service})然后生成一个实例,这个实例代表我们的代理类,每当执行代理类中的方法时候就会调用InvocationHandler中的invoke方法,这里的invoke是真正做接口解析的工作
  • 由于我们是在Android平台上使用的,因此不会走到if判断中,那么主要的就是运行loadServiceMethod(method).invoke(args)

微信截图_20210803120131.png

  • loadServiceMethod(method)方法是我们之前已经分析过的用来加载ServiceMethod的,对应我们接口中的网路请求方法
  • ServiceMethod里,通过RequestFactory.parseAnnotations方法(构建者模式)加载各网络数据以及解析注解,包含了各网路请求参数以及parameterHandlers(方法参数处理器,解析方法与方法上注解)
  • ServiceMethod通过HttpServiceMethod.parseAnnotations方法来加载网络请求适配器以及数据转换设配器等

微信截图_20210803161325.png

  • loadServiceMethod(method).invoke(args)中的invoke方法,创建了call的实现类OkhttpCall并返回了adapt方法

微信截图_20210803162021.png

OkHttpCall

  • requestFactory请求信息工作包含http各成员变量
  • args 一个包含网络接口请求参数的数组
  • callFactory用于生产okhttpClient
  • rawCall实际进行网络请求的类,就是okhttp原生的call
  • responseConverter网络响应后数据转换器
  • canceled为状态标志位,在网络请求时判断是否取消call
  • creationFailure表示构建OkHttpCall时后产生哪些异常要进行处理
  • executed 异步请求时用于判断的标志位
  • 总的来说OkHttpCall就是Retrofit封装好的okhttp库中的call对象,无论同步还是异步网络请求都是调用call对象方法

微信截图_20210803164505.png

  • 分析完OkHttpCall的创建后,回到invoke方法方法中可以发现,把创建好的OkHttpCall传进了callAdapter.adapt方法进行适配
  • 这里的callAdapter是通过loadServiceMethod(method)方法加载出来的ServiceMethod类中的callAdapter
  • 这样做的目的是为了适配各平台的call(适配器模式)

微信截图_20210803162021.png 微信截图_20210803165021.png

动态代理生产请求对象call

  • retrofit.create(MyInterface::class.java)这个方法被调用时,我们获取到了网络请求的接口myInterface,然后拿接口myInterface去调用getCall(),就好像变得很奇怪了,因为接口不能调用方法。因此这里是使用了动态代理模式,调用了Proxy.newProxyInstance方法进行拦截,调用其InvocationHandler()中的invoke方法来进行实际操作,最后返回适配好的okhttpcall类的call对象来进行实际网络请求
  • 因此myInterface.getCall()进行的网络请求实际是动态代理返回的call进行的网络请求,实质是通过okhttp库进行同步或异步网络请求

微信截图_20210803171147.png

Retrofit同步请求

  • 主要流程

export.png

  • 执行call.execute()表示进行同步请求,进入源码发现,在OkHttpCall实现类中定义了okhttp3.Call对象,再次说明了最后的实现都是通过okhttp库来实现
  • 通过OkHttpCall中的createRawCall()来创建call

微信截图_20210803175037.png

  • requestFactory.create(args)方法是用来解析创建Request对象的
  • 可以看到里面有parameterHandlers对象解析参数

微信截图_20210803181128.png 微信截图_20210803181155.png

  • 在创建好Request对象后调用callFactory.newCall(requestFactory.create(args))实质上是调用了OkHttpClient中的RealCall,后面的工作就转交给Okhttp

微信截图_20210803215856.png

  • 回到execute()方法中,接下来就是判断canceled标志位来是否取消call
  • 最返回parseResponse(call.execute()),其中call.execute()主要是okhttp的内容,parseResponse的作用是解析同步请求回来的Reponse

微信截图_20210803220605.png

  • parseResponse方法中,主要通过rawResponse.code()来获取状态码code进行相应的相应处理
  • responseConverter.convert(catchingBody)是关键的一步,作用是将返回的信息通过数据转换器转换成java对象。此时我们默认使用的是json,因此这就将json数据转换成java对象
  • 最后将成功的Reponse返回

微信截图_20210803220848.png

Retrofit异步请求

  • 异步请求与同步请求大致一样,在enqueue方法中也定义了,okhttp3.Call对象,也同样是调用createRawCall()方法创建Call

  • 在同步请求中调用的是call.execute()方法,返回的结果交由parseResponse(call.execute())方法处理,在异步请求中调用的是call.enqueue(new okhttp3.Callback() {...})方法

微信截图_20210803223114.png

  • 接下来同样使用parseResponse(rawResponse)进行数据解析
  • 最后成功时调用callback.onResponse(OkHttpCall.this, response)进行成功处理,然后我们就可以处理整个网络请求回来的结果了
  • 由此可见在Retrofit中同步与异步逻辑流程差别不是很大,Retrofit的作用就是封装okhttp库,通过动态代理让我们可以使用接口和我注解方便地进行网路请求

猜你喜欢

转载自juejin.im/post/6992394572257034247