Retrofit并不是网络请求框架,严格说只是对网络请求的一种封装,我们只需要定义一个接口类,在请求方法上加上相应的注解,甚至都不需要实现,就可以实现网络请求。但面试可就不只是要求会使用了,咱得知道内部是怎么实现的,才能顺利过关。
本篇内容,只是作为面试,提炼一下要点,建议还是先熟悉一下Retrofit的整个源码流程。关于retrofit完整源码解析,请回复【框架解析】获取视频讲解。
提到这个是因为,retrofit的精髓就在于内部的动态代理模式。
Java中的静态代理要求代理类(ProxySubject)和委托类(RealSubject)都实现同一个接口(Subject)。静态代理中代理类在编译期就已经确定,而动态代理则是JVM运行时动态生成,静态代理的效率相对动态代理来说相对高一些,但是静态代理代码冗余大,一旦需要修改接口,代理类和委托类都需要修改。
动态代理的两种实现方式:
JDK自带的java.lang.reflect.Proxy,只能代理接口类
CGLib,生产子类来实现方法增强,无需实现接口
Retrofit使用的就是JDK的动态代理。
首先,通过Builder创建Retrofit对象,在create方法中,通过JDK动态代理的方式,生成实现类,在调用接口方法时,会触发InvocationHandler的invoke方法,将接口的空方法转换成ServiceMethid, 然后生成okhttp请求,通过callAdapterFactory找到对应的执行器,比如RxJava2CallAdapterFactory,最后通过ConverterFactory将返回数据解析成JavaBena,使用者只需要关心请求参数,内部实现由retrofit封装完成,底层请求还是基于okhttp实现的。
Retrofit源码非常简练,关键类就看类成员变量,就只有下面7个。
public final class Retrofit {
private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
final okhttp3.Call.Factory callFactory;
final HttpUrl baseUrl;
final List<Converter.Factory> converterFactories;
final List<CallAdapter.Factory> callAdapterFactories;
final @Nullable Executor callbackExecutor;
final boolean validateEagerly;
....
}
ServiceMethod
核心处理类,解析接口中定义的请求方法参数和注解,通过toCall方法将其转换成okhttp的call对象,有了Call对象,就可以发送请求了。
callFactory
字面意思就是生产Call的工厂,这里的Call是okhttp包下面的Call,CallFactory默认就是OkHttpClient
HttpUrl
就是将创建retrofit对象时传入的baseUrl转换成对象,进行格式校验等。
converterFactories
数据解析器Converter,将response通过converterFactory转换成对应的JavaBean数据形式,常见解析器有,GsonConverterFactory,FastJsonConverterFactory,当然也有xml的。
callAdapterFactories
通过calladapter将原始Call进行封装,找到对应的执行器。如rxjavaCallFactory对应的Observable,转换形式Call --> Observable
callbackExecutor
主线程执行器,返回结果在UI线程执行
validateEagerly
是否立即校验所以接口方法,也就是将接口类中的方法全部转换成ServiceMethod,默认为false
定义一个注解:
@Documented //该注解类应该被javadoc工具记录
@Target(METHOD) //注解使用的地方
@Retention(RUNTIME) //注解保留期限
public @interface GET {
String value() default ""; //注解参数
}
@Documented
表示该注解类会被收录进JavaDoc,不影响运行
@Target
表示注解要使用的地方,比如@Target(METHOD)用在方法上,@Target(TYPE)用在类/接口上,@Target(FIELD)用在成员变量上
@Retention
注解保留期限,@Retention(SOURCE)在源文件有效,@Retention(CLASS)在class文件中有效,@Retention(RUNTIME)在运行期有效
注解的使用
使用反射在运行时获取注解,进行业务逻辑处理
通过预编译工具进行处理(pre-compiler tools),在编译期间生成新的类文件
根据不同BaseUrl创建不同的Retrofit对象(不可取)
@GET、@POST、@Url不仅可以传相对路径,也可以传绝对路径
大神JessYan的方案https://www.jianshu.com/p/2919bdb8d09a