Retrofit2 源码解析

Posted by boredream on January 11, 2021

Retrofit 初始化

builder模式创建,字段包括:

  • Platform platform:平台,Android或Java8等
  • HttpUrl baseUrl:host地址
  • Call.Factory callFactory:工厂模式,创建Call用。Call是一个准备好要执行的请求接口,okhttp3里的,实现类是RealCall
  • List converterFactories:工厂模式。转换器集合
    • 创建builder时会默认传入一个builtInConverter,用于转换基本的RequestBody、ResponseBody数据
    • Json数据一般我们会传入GsonConverter,进行请求和相应的bean转换
  • List adapterFactories:工厂模式。回调适配器集合
    • build时如果自定义传入RxJava2CallAdapterFactory,此外还有集合尾部默认加个ExecutorCallAdapterFactory,Call回调类型用。
  • Executor callbackExecutor:回调执行器。默认取platform的,如果是安卓的话就是主线程

Retrofit 创建接口

1
retrofit.create(Api.class)

用动态代理方式新建api接口,后面调用api.requestXX 时,会走代理,在里面做自定义处理。
代理invoke中先loadServiceMethod将普通接口方法method封装成自定义的ServiceMethod对象,先从缓存取,没有builder新建。

ServiceMethod对象也是builder模式创建,传入retrofit对象和method信息,build过程:

  1. 创建回调适配器callAdapter,如RxJavaCallAdapter。
    • 这里创建用的是工厂模式,有多个工厂,自定义的会放在前面。
    • 创建的时会传入returnType看是否和回调适配器匹配,从头到尾遍历获取到的就直接返回对应CallAdapter实现。
    • 如Observable匹配RxJavaCallAdapter,Call匹配ExecutorCallAdapter
  2. 创建返回结果转换器 responseConverter。
    • 同样是工厂模式,从多个工厂里挨个便利优先获取到的返回。
    • 这里是直接传入type annotations到工厂实现中挨个try catch尝试创建,成功就直接返回Converter实现
    • 通常是GsonResponseBodyConverter,如果是基本RequestBody、ResponseBody则返回BuiltInConverters.XXResponseConverter
  3. 遍历注解,挨个解析 parseMethodAnnotation,获取相关信息。
    • GET、POST等标签会获取 url、httpMethod、hasBody等基本信息。
    • Headers标签 获取head信息;isMultiPart、FormUrlEncodeed标签 获取相应flag信息等。
  4. 遍历所有args参数,生成相关信息保存到parameterHanderls集合里。
    • parameterHandler有不同具体实现,如Query、Body等,包含不同字段如name、valueConvert、requestConvert等
  5. 最后创建成功,加入缓存。下次如果相同method获取直接从缓存,不用再次创建

invoke里创建ServiceMethod对象后,将其和Api调用的接口方法args一起封装到OkHttpCall里,最后调用serviceMethod.callAdapter.adapt(okHttpCall); 最终return Api.接口方法需要的返回值,实际上它是代理了okHttpCall。
举个例子:

1
2
Api api = retrofit.create(Api.class); // 创建了接口对象,
Observable/Call<XXResponse> call = api.requestXX(args); // 调用某接口方法时,实际是走的动态代理invoke方法。

也就是将requestXXX的method方法信息解析成了ServiceMethod对象,联合args…一起封装成了okHttpCall对象。
再由serviceMethod.callAdapter.adapt(okHttpCall)调用,最后返回Observable。而这个obs实际是代理了okHttpCall。

拆开callAdapter.adapt方法具体看,以RxJava2CallAdapter为例:
RxJava2CallAdapterFactory.create() 创建的都是同步的,会先创建个CallExecuteObservable的responseObservable,又返回类型是Observable<自定义类>,所以根据isBody以responseObservable为参数创建 BodyObservable observable,最后根据Single/Flowable等类型判断,确定直接return BodyObservable 对象。

因此,当返回值如Observable订阅subscribe调用的时候,就会走到CallExecuteObservable中,调用 subscribeActual方法,这个方法里会调用 okHttpCall.execute ,而OkHttpCall 里具体请求就是用OkHttp3实现的,字段里有serviceMethod以及args,OKHttpCall里的execute方法,会先createRawCall创建RealCall对象,这里就到OkHttp3的部分了。
createRawCall会先调用serviceMethod.toRequest(args)生成请求对象,这里会根据之前生成的方法信息和参数信息。再用生成的Request创建RealCall对象,最终调用realCall.execute()实际执行网络接口请求,执行方法返回Response对象,最后再用 responseConverter进行转换,如RxJava2CallAdapter会通过observer.onNext回调下去。

总结

Api interface 相当于配置表,每个方法是一个接口。用标签、参数、返回值确定了接口请求和相应的基本信息。
使用「动态代理」的技术,retrofit.create 创建的 Api,在调用这些代表接口的方法时,实际上走了代理的invoke,进行了包装。包装了网络请求需要的一些基础信息,地址、请求类型、参数、响应类型等。
发起的实际执行和返回数据的处理,都通过invoke实现了加工处理。处理提供多种自定义方式,如数据转换方式、回调方式、请求的实际执行框架等,十分灵活。

问题

为什么要用工厂模式?

  • 封装性好,客户不需要知道细节。如框架自带的RxJava2CallAdapterFactory.create
  • 扩展性高,按需求实现Factory接口,用指定的参数根据需求自定义创建对象

convert和callAdapter为什么要用集合?

比如callAdapter,有的接口方法返回值是Observable有的是Call,需要不同的解析处理。
同理convert,有的提交数据是gson,有的是其它,conver承担了请求和相应的转换,都需要处理。