将一个Java接口翻译成一个Http请求,然后用OkHttp去发送这个请求
一 入口类 Retrofit 成员变量
private final HttpUrl baseUrl;//网络请求基地址
private final List<Converter.Factory>converterFactories;//数据转换器工厂集合
private final List<CallAdapter.Factory> adapterFactories;//网络请求适配器工厂集合
private final okhttp3.Call.Factory callFactory;//底层进行网络请求工厂
private final Executor callbackExecutor;//回调方法执行器
/ServiceMethod是对业务接口中方法的注解进行解析之后得到的对象,该对象包含了访问网络的除了方法参数值之外的所有必要信息;如数据转换器、网络请求适配器、网络请求工厂、基地址、Http方法等等。
private final Map<Method,ServiceMethod> serviceMethodCache =newLinkedHashMap<>();
Retrofit.bulid()方法 初始化 外观模式
二 动态代理
https://www.ibm.com/developerworks/cn/java/j-lo-proxy1/ 动态代理的机制
http://www.ibm.com/developerworks/cn/java/j-jtp08305.html 动态代理的Decorator
GitHubServiceservice = retrofit.create(GitHubService.class);
create方法就是返回了一个Proxy.newProxyInstance动态代理对象
动态代理是java中的字节码生成技术。通过接口生成代理类,并将代理类的实现交给InvocationHandler作为具体的实现 ,
动态代理作为 Decorator
就是你要调用某个class方法的前后 ,你可以很方便的插入些你想要执行的额外代码
一个动态代理类可以充当所有接口的 Decorator 或 Proxy,这样就不用每个接口都编写一个具体的实现类
Call <List<Repo>> repos = service.listRepos("octocat");
执行流程:
service对象其实是一个动态代理对象,并不是一个真正的GitHubService接口的implements产生的对象,当api对象调用listRepos方法时会被动态代理拦截,然后调用Proxy.newProxyInstance方法中的InvocationHandler对象的invoke方法。
invoke方法会传入3个参数:
Object proxy, 代理对象
Method method,调用的方法 listRepos
Object... args 方法参数 octocat
Retrofit里的动态代理比较巧妙。它不关心proxyd,只是单纯的为了拿到了这个method上所有的注解 生成ServiceMethod对象,生成的ServiceMethod对象和args构造生成了HttpCall 可以发起HTTP请求的类
总结:简化复杂的网络请求,通过动态代理的去处理解析与拼装HTTP请求
三 核心类 ServiceMethod
一个ServiceMethod对象对应于一个 API interface 的一个方法
主要成员变量
final okhttp3.Call.Factory callFactory; //负责创建 HTTP 请求
final CallAdapter callAdapter; //请求适配器 把retrofit2.Call<T>转为T
private final Converter responseConverter; 负责把服务器返回的数据(JSON、XML、二进制或者其他格式,由ResponseBody封装)转化为T类型的对象
private final Headers headers; //请求头信息
private final ParameterHandler[ ] parameterHandlers;//负责解析 API 定义时每个方法的参数,并在构造 HTTP 请求时设置参数
初始化过程 build()方法
callAdapter= createCallAdapter();//将遍历一个CallAdapter.Factory列表,根据方法返回值类型和注解提供需要的网络请求适配器
responseType=callAdapter.responseType();
responseConverter= createResponseConverter();//;即根据方法返回值类型和注释从retrofit中获取对应的转换器
for(Annotation annotation :methodAnnotations) {
parseMethodAnnotation(annotation);//解析Method的注解 给ServiceMethod的成员变量赋值
}
for(intp =0;p < parameterCount;p++) {
...
parameterHandlers[p] = parseParameter(p,parameterType,parameterAnnotations);
//方法中的每个参数创建一个ParameterHandler对象,该对象的创建过程就对方法参数中的Body、PartMap、Part、FieldMap、Field等注解进行解析
}
核心:okhttp3.Call.Factory,CallAdapter.Factory和Converter.Factory三个工厂类,模块之间、类之间通过接口进行依赖,创建十么样的实现类交给工厂去处理,工厂同样也是接口,添加怎样的工厂,则在最初构造Retrofit对象时决定,各个模块之间完全解耦,每个模块只负责自己的责任。
四 执行HTTP请求
4.1 OkHttpCall类中execute() 同步发起网络请求,执行分析
createRawCall()
1调用了serviceMethod.toRequest(args)来创建okhttp3.Request对象,之前解析参数注解的parameterHandlers在这里给HTTP请求 设置参数传进入,最后RequestBuilder build()生成Request请求
2 再调用serviceMethod.callFactory.newCall(request)来创建okhttp3.Call,这里之前准备好的callFactory同样也派上了用场,由于工厂在构造Retrofit对象时可以指定,所以我们也可以指定其他的工厂,来使用其它的底层 HttpClient 实现。这里Retrofit2就和Okhttp结合起来了 网络请求的执行业务流程都交给Okhttp来处理
return parseResponse(call.execute());
调用okhttp3.Call#execute()来执行网络请求,这个方法是阻塞的,执行完毕之后将返回收到的响应数据。收到响应数据之后,进行状态码的检查,再调用serviceMethod.toResponse(catchingBody)来把响应数据转化成我们需要的数据类型对象。使用之前准备好的responseConverte转化数据。
4.2 enqueue(Callback callback) 异步执行
这里的异步交给了okhttp3.Call#enqueue(Callback responseCallback)来实现,并在它的 callback 中调用parseResponse解析响应数据,并转发给传入的 callback
五 CallAdapter 接口
请求的适配化OkHttpCall --Adapter--> RxJava/java8/UICallback
通过适配器实现OkHttpCall到其它类型(比如RxJava等第三方库)的适配转换
public Interface CallAdapter<T> {
Type responseType();//该请求适配器返回的数据类型
T adapt(Call call);//该请求适配器对原始Call的再次封装,如Call到Observable,
abstract class Factory {
public abstract CallAdapter get(Type returnType, Annotation[] annotations, Retrofit retrofit);//获取网络请求适配器
protected staticType getParameterUpperBound(intindex, ParameterizedType type)
{returnUtils.getParameterUpperBound(index, type); }
protectedstaticClass getRawType(Type type) {returnUtils.getRawType(type); }
}
ExecutorCallAdapterFactory 是Retrofit默认实现
该对象存储一个回调执行器,异步请求将相应的结果交给callbackExecutor回调执行器去执行Android平台Retrofit2会使用主线程handler构造一个ExecutorCallAdapterFactory,调用enqueue(Callback),callback回调会在主线程中回调
5.1 Retrofit2和RxJava的结合使用
1 RxJavaCallAdapterFactory类
RxJava对请求进行包装,它将根据网络请求生成一个Observable进行流式任务执行
getCallAdapter方法中对返回值的泛型类型进行了进一步检查,例如我们声明的返回值类型为Observable,泛型类型就是List,这里对retrofit2.Response和retrofit2.adapter.rxjava.Result进行了特殊处理,有单独的 adapter 负责进行转换,其他所有类型都由SimpleCallAdapter负责转换
2 SimpleCallAdapter#adapt方法
创建了一个Observable,传入了CallOnSubscribe类,同时使用了一个OperatorMapResponseToBodyOrError操作符,用来把retrofit2.Response转为我们声明的类型,或者错误异常类型
3 CallOnSubscribe#call方法
clone 了原来的 call,因为okhttp3.Call是只能用一次的,所以每次都是新 clone 一个进行网络请求;创建了一个叫RequestArbiter的 producer,把这个 producer 设置给 subscriber;
Producer机制 简单的理解
Subscriber 都是被动接收 Observable 传递 过来的数据,然后Subscriber做处理。
但要是 Observable 发得太多,Subscriber 处理不过来,那就有问题了,所以就有了一种 Subscriber 主动 pull 的机制,而这种机制就是通过 Producer 实现的。给 Subscriber 设置 Producer 之后(通过Subscriber#setProducer方法),Subscriber 就会通过 Producer 向上游根据自己的能力请求数据(通过Producer#request方法),而 Observable 收到请求之后再根据请求的量给 Subscriber 发数据。
RequestArbiter#request方法
执行call.execute() 获取到Response响应数据,并且发送给下游接收
Observable.lift(OperatorMapResponseToBodyOrError.instance())
lift操作符 负责接收原始的Observable发出的事件,并在response.body()并发送给下游。这里,body()返回的就是我们声明的泛型类型了
Call<R>->Response<T>->Observable<T> 执行流程
1 Observable.subscribe,触发 API 调用的执行;
2 CallOnSubscribe#call,clone call,创建并设置 producer;
3 subscriber 被设置了 producer 之后调用RequestArbiter#request,在 request 中发起网络请求,把处理结果发给下游;
4 OperatorMapResponseToBodyOrError$1#onNext,把 response 的 body 发给下游
5 最终就到了我们 subscribe 时传入的回调里面了;
六 概括Retrofit2的话,借鉴了服务器编程中AOP思想,利用动态代理技术通过接口在运行时拦截方法,接着通过解析注解拼装HTTP请求;最后包装了OkHttpCall生成真正的请求类 发起网络请求, 通过抽象工厂让各个模块直接解耦,完成对原数据Respone的Conver,实现了对Rx、线程的Adapter ,