写点什么

Android 网络框架之 Retrofit 源码解析,android 嵌入式开发及实训答案

用户头像
Android架构
关注
发布于: 刚刚

我们进源码里面看一下,具体做了啥操作;



这里主要做了两步操作:


1、首先第一步是通过解析这个 baseUrl 并返回一个 HttpUrl 对象; 2、第二步是将第一步创建的 HttpUrl 对象赋值给 Builder;


这里我们主要看第一步的具体操作,这里的逻辑是在 HttpUrl 的 parse(@Nullable HttpUrl base, String input)里,通过解析 URL,判断该请求的 scheme 是为 http 还是 https,如果不是这其中一个,那么就会抛出异常,源码我们大致看一下;



然后下面还会解析 URL,获取到主机地址 host,端口号 port,具体源码我就不贴了,感兴趣的可以跟着源码看一下;

4.3、Converter.Factory

这个我们上面在接受 Retrofit 的成员变量的时候有提过,是用于创建 Converter 的工厂,使用了抽象工厂的设计模式,而 Converter 是用来将请求返回的数据,转化为对应平台的数据,而这里,我们使用的是 Gson 平台;


我们先来看一下这个 Converter.Factory,看看其背后是怎么实现的;



从源码可以看出,Converter.Factory 是 Converter 的内部类,主要有两个方法,一个是 requestBodyConverter,用于将请求的 RequestBody 转换为对应的转换器 Converter;


另一个方法是 responseBodyConverter,用于将返回的返回体 ResponseBody 转换为对应的转换器 Converter;


而转换器 Converter 里面只有一个方法 convert,用于将返回的数据转换为对应的类型;


我们在创建 Retrofit 的实例时,是通过 GsonConverterFactory.create()来创建对应的转换器工厂的,下面我们来看看这个 Gson 的转换器工厂是怎么实现的;


先来看一下这个 create()的方法;



最终是走的这里,进行了简单的赋值;



GsonConverterFactory 这个工厂最重要的还是 responseBodyConverter 和 requestBodyConverter 方法,下面我们来具体分析;


  • requestBodyConverter:



在 requestBodyConverter 方法里面,通过 class 的 Type 类型,创建了 Gson 的 TypeAdapter,这个 TypeAdapter 很熟悉,就是我们使用 gson 解析会用到的类,最终通过 TypeAdapter 和 gson 的参数创建了 GsonRequestBodyConverter 对象,下面来瞄一眼这个类的代码;



这个类的源码很简单,我们主要 convert()这个方法;


这个方法的逻辑就是将传进来的 value 值通过 TypeAdapter 将其转化为 ByteString,然后再传进 RequestBody 作为参数来构建 RequestBody 对象;


这个方法我们先了解到这里,后面在这个 requestBodyConverter 调用的地方再来讲一下;


  • responseBodyConverter:



这个方法和上面那个 requestBodyConverter 方法有点类似,也是通过 class 的 Type 类型,创建了 Gson 的 TypeAdapter,最终通过 TypeAdapter 和 gson 的参数创建了 GsonResponseBodyConverter,同理,我们也来看一下这个类的实现吧;



源码很简单,这里我们也是关注 convert()这个方法;


这里的逻辑有没有很熟悉,就是我们经常用的 gson 解析,通过 TypeAdapter 读取 JsonReader 的数据,返回对应的数据类型,这里的参数 ResponseBody 就是我们上面 GsonRequestBodyConverter 的 convert 方法生成的;


到这里 GsonConverterFactory 就讲的差不多了,后面我们在用到的地方再详细讲一下;

4.5、CallAdapter.Factory

CallAdapter.Factory,从命名可以看出,是用来创建 CallAdapter 的工厂类,使用了抽象工厂的设计模式,而 CallAdapter 是用于将 Call 转化为我们所需要的请求类型,比如将 Call 转化为 RxJava 的调用类型;


而 CallAdapter 里面是通过 adapt 方法来进行转换的,adapt 是接口的一个方法,交给子类去实现,这个方法的逻辑,我们下面将 Retrofit 的解析时,再统一讲解,这里是需要了解这是一个转换的方法即可;



下面我们来看看创建 CallAdapter 的工厂里面都有哪些方法,分别是用来干嘛的;



这个 Factory 的逻辑很少,只有几个方法,这里我们主要关注 get 方法,通过 get 方法来获取 CallAdapter 的对象,同理,这里也是交给子类去实现;


而上面我们 Retrifit 的创建,在 CallAdapter.Factory 的添加时,使用了 RxJava 的工厂,也就是 RxJava2CallAdapterFactory,用于将 Call 请求转换为 RxJava 对应的请求;


下面我们来看看这个 RxJava2CallAdapterFactory 的实现逻辑吧;


RxJava2CallAdapterFactory 的创建,也是通过 RxJava2CallAdapterFactory.create()的方法,那么我们来看下这个 create 方法做了啥?



只是简单的 new 了一个 RxJava2CallAdapterFactory,而构造方法里也没有其他的逻辑了,只是对 Scheduler 进行赋值,而这里创建时,传的是 null;


上面我们看完 RxJava2CallAdapterFactory 的创建后,下面我们来看一下 RxJava2CallAdapterFactory 是怎么通过 get 方法创建一个 CallAdapter 的;


public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {


Class<?> rawType = getRawType(returnType);


if (rawType == Completable.class) {


// 创建 RxJava2CallAdapter


return new RxJava2CallAdapter(Void.class, scheduler, isAsync, false, true, false, false,


false, true);


}


...


// 创建 RxJava2CallAdapter


return new RxJava2CallAdapter(responseType, scheduler, isAsync, isResult, isBody, isFlowable,


isSingle, isMaybe, false);


}


这个方法职责很明确,就是根据各种参数来创建 RxJava 的 CallAdpter,也就是 RxJava2CallAdapter;


这里我们来重点关注一个 RxJava2CallAdapte 的 adapt 方法的逻辑;


public Object adapt(Call<R> call) {


// 第一步:根据是否是异步的参数创建对应的 Observable


Observable<Response<R>> responseObservable = isAsync


? new CallEnqueueObservable<>(call)


: new CallExecuteObservable<>(call);


Observable<?> observable;


// 第二步:根据各种判断,再封装一层 Observable 返回


if (isResult) {


observable = new ResultObservable<>(responseObservable);


} else if (isBody) {


observable = new BodyObservable<>(responseObservable);


} else {


observable = responseObservable;


}


...


return observable;


}


这个方法的逻辑并复杂,主要是将 Call 请求转化为 RxJava 的请求,最终返回一个 RxJava 的被观察者:Observable,用于进行 RxJava 类型的网络请求,如上面的示例;


这个方法的逻辑主要有两步,我们先来看一下第一步创建的被观察者,这里会先判断是否是异步,如果是异步的话,那么就创建 CallEnqueueObservable,否则就创建 CallExecuteObservable;


这两个的区别就是,在调用订阅(subscribe)的时候,会执行 CallEnqueueObservable 的 subscribeActual 方法,最终是通过 OkHttpCall 的 enqueue 方法来执行异步请求;


而 CallExecuteObservable 在调用订阅(subscribe)的时候,也会执行 CallEnqueueObservable 的 subscribeActual 方法,在这个方法里,就直接调用 OkHttpCall 的 execute 方法来执行同步请求;


而第二步的封装,这里我们主要以 BodyObservable 来进行讲解,这个类会对订阅的观察者进行封装,在 onNext 方法中将 body 返回;这一步可以理解为对返回的结果进行处理;



这里是 RxJava 的用法,我默认你是会的,如果对 RxJava 还不熟悉的同学,可以后面去看看 RxJava 的用法;


到此,Retrofit 的 CallAdapter.Factory 的逻辑就先告一段落了,下面我们来看看 Retrofit 的最终 build()方法的逻辑;

4.5、Retrofit.Builder#build

废话不多说,我们直接撸源码;


public Retrofit build() {


// 判断当 callFactory(OkHttpClient)为空,就重新创建一个 OkHttpClient 进行赋值;


okhttp3.Call.Factory callFactory = this.callFactory;


if (callFactory == null) {


callFactory = new OkHttpClient();


}


// 判断 Executor 为空时,就用 Platform 的默认 Executor 进行赋值,上面我们讲过,这里面使用的是主线的的 Handler;


Executor callbackExecutor = this.callbackExecutor;


if (callbackExecutor == null) {


callbackExecutor = platform.defaultCallbackExecutor();


}


// 通过添加的 CallAdapter.Factory 来创建一个新的 CallAdapter.Factory 集合;


List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);


// 添加 Platform 的默认 CallAdapter.Factory,如果我们没有添加 CallAdapter.Factory,那么就会使用这个 Platform 的默认 CallAdapter.Factory; callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));


// 创建 Converter.Factory 的集合


List<Converter.Factory> converterFactories = new ArrayList<>(


1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());


// Add the built-in converter factory first. This prevents overriding its behavior but also


// ensures correct behavior when using converters that consume all types.


// 添加默认的 Converter.Factory


converterFactories.add(new BuiltInConverters());


// 添加自定的 Converter.Factory


converterFactories.addAll(this.converterFactories);


// 添加 Platform 的默认 Converter.Factory


converterFactories.addAll(platform.defaultConverterFactories());


// 最终创建 Retrofit 实例;


return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),


unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);


}


这个 build()方法,主要是做各种参数的赋值,最终通过参数来创建 Retrofit 的实例,那么到这里 Retrofit 的创建就差不多将完了,下面我们将会学习到 Retrofit 的核心;


为什么我们可以通过接口定义一个类型,就可以执行请求了,对于这些方法的解析,以及参数的赋值的操作是在哪里呢?


这么就涉及到 Retrofit 使用的一个很重要的设计模式了,也就是动态代理设计模式;


5、Retrofit 的核心,动态代理



5.1、什么是代理?

举个例子,假如我要去超市买水果,可是我好懒,周末就想呆在家里不想出门,但是心里又很想吃水果,那怎么办呢?


只能打开外卖 App,在上面买完之后,由外卖小哥送过来,这时候,我就通过中介,外卖 App 来买到水果,而这个过程叫做代理;


不直接操作,而是委托第三方来进行操作,从而达到目的;


而 Java 的代理分为静态代理和动态代理;

5.2、什么是静态代理?

如果代理类在程序运行之前就已经存在了,那么这种代理方式就被称为静态代理;


还是以上面的例子,我要买水果,来定义一个买水果的接口 Operator;


public interface Operator {


// 买水果


void buyFruit();


}


而我们的代理类外卖 App 需要实现这个接口,同时,将需要委托的对象传进来,在 buyFruit 的过程中,做了一些出来,比如去超市取货,取完货之后,再送货;


public class AppAgent implements Operator {


private Operator operator;


public AppAgent(Operator operator) {


this.operator = operator;


}


@Override


public void buyFruit() {


// 1、在 App 上,提供商品给用户下单


// 2、根据订单去超市采购水果


operator.buyFruit();


// 3、送货给客户


}


}


委托的对象,超市:


public class Market implements Operator {


@Override


public void buyFruit() {


// 到超市买水果


}


}


那么最终的实现效果就是,我们通过外卖 App 的一顿操作,从超市买到了水果,如下:


public class Main {


public static void main(String[] args) {


// 委托对象,超市;


Market market = new Market();


// 代理对象,外卖 App;


AppAgent appAgent = new AppAgent(market);


// 通过外卖 App 的代理,从超市买到了水果;


appAgent.buyFruit();


}


}


以上就是我们静态代理的过程,这个例子只是举了买水果这个过程,但是如果我还想要买菜,买生活用品等一系列东西呢?


我就得在接口 Operator 里面再多新增好几个方法,同样的代理类也要跟着去重写一堆的方法,但是这些方法做的操作其实都是一样的,都是买这个动作,但是我们不得已,新增一种类型,我们就得在代理类里面再重写并调用;


那么这个过程其实是可以抽出来的,这种方式就叫做动态代理;

5.3、动态代理

动态代理,和静态代理不同的是,动态代理的方法是运行后才创建的,而静态代理是运行前就存在的了;


说白了,和静态代理不同的是,动态代理的方法都是在运行后,自动生成的,所以叫动态代理;


下面我们来看看动态代理是咋用的;


在使用动态代理的时候,被代理类需要实现 InvocationHandler 这个接口,,这个 invoke 方法是在动态生成的代理类中调用的,对应着我们上面在静态代理 operator.buyFruit()这个方法的调用,下面来看一下这个方法对应的参数;


public interface InvocationHandler {


// Object proxy:接口的具体实现类;


// Method method:解析之后自动生成的方法;


// Object[] args:方法对于的参数;


Object invoke(Object proxy, Method method, Object[] args);


}


而最终运行时生成的代理类,一般名称会是Proxy1 这种,通过 Proxy.newProxyInstance()方法来生成的,这个下面会讲到,先来看一下下面的伪代码;


public final class $Proxy0 extends Proxy implements Operator {


public final boolean buyFruit() {


// h 是 InvocationHandlel,调用了 invoke 方法;


super.h.invoke(this, m1, (Object[])null);


}


}


}


在生成的代理类中,会实现我们的接口,并重写方法,在方法里面通过 InvocationHandler 回调参数到 invoke 方法里,最终通过反射调用被代理对象的方法;


而我们通过实现这个 InvocationHandler 接口,在 invoke 方法里面,通过 method.invoke(object, args)可以来调用被代理的方法,然后我们可以在这个 method.invoke(object, args)之前或者之后做一些处理,这样所以的方法都可以一并进行处理,而不是每次新增一个方法,就得重写一遍逻辑;


下面来看一下具体实现:


public class CustomProxy implements InvocationHandler {


private Object object;


public CustomProxy(Object object) {


this.object = object;


}


@Override


public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {


// 1、在 App 上,提供商品给用户下单


// doSomeThing();


// 2、根据订单去超市采购东西(在这个方法之前或者之后都可以统一处理操作)


Object invoke = method.invoke(object, args);


// 3、送货给客户


// doSomeThing();


return invoke;


}


}


下面来看一下,最终的调用;


public class Main {


public static void main(String[] args) {


// 创建被代理类


CustomProxy customProxy = new CustomProxy(new Market());


// 动态生成代理类


Operator proxyInstance = (Operator) Proxy.newProxyInstance(Operator.class.getClassLoader(), new Class[]{Operator.class}, customProxy);


// 调用对应的方法


proxyInstance.buyFruit();


}


}


这里通过 Proxy.newProxyInstance()方法,动态生成代理类 $Proxy0 这种,这里涉及到的反射的知识,就不再赘述了;


然后动态代理类调用方法,最终会走到 CustomProxy 的 invoke()方法,然后我们在这个方法里面通过 method.invoke(object, args)来进行最终的代理调用,而在这个最终的代理调用的前后,我们可以实现自定义的逻辑;


这个实现了 InvocationHandler 接口的 CustomProxy,更像是一个拦截类,在代理方法的调用过程中进行拦截,然后再实现我们的自定义逻辑;


至此,动态代理你理解了吗?没有理解也没关系,多看几遍,多练几遍就可以了;


6、Retrofit 的动态代理



6.1、Retrofit 为什么要使用动态代理?

首先,让我们来想一个问题,Retrofit 为什么要使用动态代理?


使用动态代理的好处就是在调用方法之前,我们可以统一做一些操作,而不必新增一个方法就去写一遍逻辑;


而 Retrofit 巧妙的使用了动态代理在调用接口的方法之前,统一的去解析处理 Header 和 URL 等操作;


这样就不用每次在新增一个请求的方法,就去写一遍这个解析的逻辑;


那么接下来我们来看看 Retrofit 的怎么解析这些接口的;

6.2、Retrofit 是怎么使用动态代理的?

下面我们来看一下 Retrofit 的 create 的方法,动态代理的逻辑是在这里实现的;


public <T> T create(final Class<T> service) {


...


// 验证接口的参数以及配置是否正确


if (validateEagerly) {


eagerlyValidateMethods(service);


}


// 动态代理


return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },


new InvocationHandler() {


private fin


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


al Platform platform = Platform.get();


private final Object[] emptyArgs = new Object[0];


@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)


throws Throwable {


// 判断是否是 Object,如果是的话,就直接调用方法返回


if (method.getDeclaringClass() == Object.class) {


return method.invoke(this, args);


}


// 判断是否是 Java8 平台的默认方法类型,如果是的话,就调用 Java8 平台的 invokeDefaultMethod 方法


if (platform.isDefaultMethod(method)) {


return platform.invokeDefaultMethod(method, service, proxy, args);


}


// 解析方法;


return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);


}


});


}


这里我们将这个方法分为两步;


第一步: eagerlyValidateMethods 方法,这个方法的逻辑是用于加载接口的配置,用于判断接口对应的 header,body 以及方法的参数等配置是否正确,如果不正确那么就会抛出异常;


第二步: loadServiceMethod 方法,这个方法的逻辑主要是用于解析我们在接口配置的注解以及参数,比如 header,body,url 等等;


这里我们重点关注第二步的 loadServiceMethod 方法方法;


我们来看一下其源码的具体实现;


ServiceMethod<?> loadServiceMethod(Method method) {


// 先从缓存 map 集合里面获取 ServiceMethod;


ServiceMethod<?> result = serviceMethodCache.get(method);


if (result != null) return result;


synchronized (serviceMethodCache) {


result = serviceMethodCache.get(method);


if (result == null) {


// 如果从缓存 map 里面获取不到 ServiceMethod,那么再通过解析注解,获取到 ServiceMethod 对象;


result = ServiceMethod.parseAnnotations(this, method);


// 将解析后的 ServiceMethod 对象存入到 map 集合中;


serviceMethodCache.put(method, result);


}


}


return result;


}


这里做的操作很简单,就是获取 ServiceMethod,而在获取 ServiceMethod 的过程中,会先从缓存的 map 中获取,如果获取不到了再进行解析,这样就不必获取一次 ServiceMethod,就去解析一次,比较耗性能;


而这个 ServiceMethod 的类是个抽象类,只有两个方法,一个是静态的 parseAnnotations 方法,一个是抽象的 invoke 方法;


我们先来看一下这个 parseAnnotations 方法;


static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {


// 通过解析接口方法的注解,获取 RequestFactory


RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);


...


// 解析注解并获取 ServiceMethod 对象


return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);


}


这个方法的逻辑也不是很复杂,主要分为两步;


第一步: 获取 RequestFactory;


第二步: 获取 ServiceMethod;


我们先来看第一步的操作;


static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {


return new Builder(retrofit, method).build();


}


通过 Builder 来创建 RequestFactory,来看看这个 Builder 做了啥操作;


Builder(Retrofit retrofit, Method method) {


this.retrofit = retrofit;


this.method = method;


// 获取方法所有的注解,包括自己声明的以及继承的


this.methodAnnotations = method.getAnnotations();


// 获取方法参数的所有类型,包含泛型;


this.parameterTypes = method.getGenericParameterTypes();


// 获取方法参数上的所有注解


this.parameterAnnotationsArray = method.getParameterAnnotations();


}


这个方法的逻辑很简单,就是做一些赋值操作,这里需要注意的是这几个反射的方法,下面的 build 方法会用到;


RequestFactory build() {


for (Annotation annotation : methodAnnotations) {


// 遍历方法的注解,解析方法的参数配置,获取到请求的 url,header 等参数


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]);


}


...


// 根据上面解析的参数配置,创建 RequestFactory


return new RequestFactory(this);


}


这个方法的逻辑就比较重要了,我们在接口的方法里面定义的相关 url,header 等注解,最终就是在这里解析并转化为 okhttp 请求的 Call,那么我们来看看这里到底是怎么解析的;


先来看一下 parseMethodAnnotation 这个方法, 这个方法的主要逻辑是用于解析方法注解的配置信息;



下面我们来看看这个类的具体实现;



这个方法的逻辑比较多,我们大致看一下就可以了,这里面做的主要职责就是通过注解 Annotation,获取到 url,header,isMultipart 等参数,并将其赋值给建造者 Builder 的成员变量;


对于这个方法,这里就不多说了,感兴趣的跟着源码去看一下;


而第二个方法 parseParameter,也是遍历上面获取到的方法的参数类型 parameterTypes 以及方法参数的注解 parameterAnnotationsArray,来解析并获取相关配置,而这个方法最终是调的 parseParameterAnnotation 方法的逻辑;


主要是用于解析这里的逻辑:



下面我们来看看具体实现;



这个 parseParameterAnnotation 方法的逻辑和上面的 parseMethodAnnotation 方法有点类似,也是通过判断对于的类型来进行解析,这里源码过长,就不贴出来了;


这里我们就找其中一个 Query 的解析来进行分析;


省略前面的代码


...


else if (annotation instanceof Query) {


...


// 将注解 annotation 强转为 Query


Query query = (Query) annotation;


// 获取注解 Query 对应的值;


String name = query.value();


...


if (Iterable.class.isAssignableFrom(rawParameterType)) {


// 判断这个参数的类型为 Class 类型;


...


// 创建 ParameterHandler 的子类 Query


return new ParameterHandler.Query<>(name, converter, encoded).iterable();


}


...


}


...


省略后面的代码


这里最终解析获取的是 ParameterHandler.Query 类,这个类里面有个 apply 的方法,会在接口请求的时候会调用到,目的是通过请求的 RequestBuilder 将解析出来的参数,添加到 RequestBuilder 里去;



这里我们了解一下就可以了;

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
Android 网络框架之Retrofit源码解析,android嵌入式开发及实训答案