独特的架构方式,Retrofit源码简析。

retrofit2.0

2016/07/21
上海
Read the fucking source code。

    Retrofit,Type-safe HTTP client for Android and Java 。
    GitHub:http://square.github.io/retrofit

开始之前,先回想下一个网络请求的基本姿势(默认框架搭建完成):
1,生成请求参数,确定接口
2,利用NetWork模块,发送到指定API
3,响应成功,反序列
4,响应失败,做某些处理
5,线程调度,结果交给前台

Retrofit作为NetWork框架,也不例外。
1,以接口+注解的形式,生成请求参数,确定接口
2,利用CallFactory生成NetWork模块,发送到指定API
3,响应成功,利用ConverterFactory反序列
4,响应失败,做某些处理
5,请求结果经过CallAdapterFactory包装
6,CallAdapterFactory包装包装后,线程调度,结果交给前台

目录:
1,我们配置Retrofit时,到底发生了什么?
2,Retrofit.create(final Class<T> service)都做了什么?
3,ServiceMethod 是什么?
4,OkHttpCall 是什么?
5,serviceMethod.callAdapter.adapt(okHttpCall)是什么鬼?
6,CallFactory、okHttpCall、CallAdapter之间的关系?


问题一:我们配置Retrofit时,到底发生了什么?

</br>

//Retrofit构造器
new Retrofit.Builder()        
//配置服务器
.baseUrl(UrlHelp.SERVER_IP)                                     
//反序列工具生成器
.addConverterFactory(XmlToJsonConverterFactory.create())
.//结果包装工具生成器(不大好描述..)        
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())       
//NetWork工具生成器
.callFactory(HttpClient())        
//线程调度
.callbackExecutor()            
.build();

** 配置:**
ConverterFactory 反序列工具生成器
CallAdapterFactory 结果包装工具生成器 默认为ExecutorCallAdapterFactory
okhttp3.Call.Factory NetWork工具生成器 默认为OkHttpClient
CallbackExecutor 线程调度

配置的是Retrofit的功能模块,Retrofit将网络请求流程中的各个关节(是的,关节)部位打断,使各个模块之间相关性降到最低,再通过“配置”的方式开放出来,应对复杂的使用环境。

Retrofit(
  okhttp3.Call.Factory callFactory, 
  HttpUrl baseUrl,
  List<Converter.Factory> converterFactories, 
  List<CallAdapter.Factory> adapterFactories,    
  Executor callbackExecutor, boolean validateEagerly) {  
    this.callFactory = callFactory; 
    this.baseUrl = baseUrl;  
    this.converterFactories = unmodifiableList(converterFactories); 
    // Defensive copy at call site.  
    this.adapterFactories = unmodifiableList(adapterFactories); 
    // Defensive copy at call site.  
    this.callbackExecutor = callbackExecutor;  
    this.validateEagerly = validateEagerly;
}

.build()方法new Retrofit()实例并返回,new Retrofit()时传入配置信息。


问题二:Retrofit.create(final Class<T> service)都做了什么?

</br>

mRetrofit.create(RetorfitInterfaces.UserInfoServer.class)        
.sendPost(userId)        
.enqueue(call);

create(final Class<T> service),传入自定义接口,返回接口实例。
在外部使用中,这是最直接的感受,实际上返回的是代理对象。

//仅摘取核心部分
public <T> T create(final Class<T> service) {      
......
  return (T) Proxy.newProxyInstance(
          ...    
          new InvocationHandler() {        
            .....
            @Override 
            public Object invoke(Object proxy, Method method, Object... args) throws Throwable {
                ......
                //加载ServiceMethod
                ServiceMethod serviceMethod = loadServiceMethod(method);
                //加载OkHttpCall 
                OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
                //调用callAdapter.adapt(okHttpCall)
                return serviceMethod.callAdapter.adapt(okHttpCall);
        }
      });
}

这部分源码写的很直观,简单来说当调用接口中的方法时,都会运行InvocationHandlerinvoke()方法。

重点就在invoke(Object proxy, Method method, Object... args)方法中的三句代码:

ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);


问题三:ServiceMethod 是什么?

</br>
(以下省略适配、优化等细节代码)

//调用Retrofit.loadServiceMethod(method);加载ServiceMethod;
serviceMethod = loadServiceMethod(method);
ServiceMethod loadServiceMethod(Method method) {
  ServiceMethod result;
   ....
      //通过 ServiceMethod.Builder构造器创建实例
      result = new ServiceMethod.Builder(this, method).build();
   ....
  return result;
}
public Builder(Retrofit retrofit, Method method) {
//持有了retrofit实例,retrofit持有前面说到的各配置组件,
//也就是说ServiceMethod相当于持有各配置组件,
//变相的将四大组件组装在了一起。
  this.retrofit = retrofit;

  ..注解解析相关...
}
public ServiceMethod build() {
.....

//创建CallAdapter实例,createCallAdapter()是ServiceMethod.Builder的私有方法,在此简写
  callAdapter = createCallAdapter(){
     ....
     //调用了Retrofit实例的CallAdapter();CallAdapter()是Retrofit的公共方法,在此简写
     return retrofit.callAdapter(returnType, annotations){
         ...
               //Retrofit利用配置中的CallAdapterFactory获取CallAdapter实例
               return CallAdapterFactory.get();
           };
   };

......

  //创建responseConverter 反序列工具实例,createResponseConverter()是ServiceMethod.Builder的私有方法,在此简写
  responseConverter = createResponseConverter(){
            ....
      //调用Retrofit实例的responseBodyConverter()方法
      return retrofit.responseBodyConverter(responseType, annotations){
                    ....
                   //利用converterFactory工厂创建反序列工具
                    return converterFactory.responseBodyConverter();
             }
   };

...注解相关...  

  //调用ServiceMethod的构造函数ServiceMethod(Builder builder);创建实例
   return new ServiceMethod<>(this);
}

//ServiceMethod.Builder构造器(注意还不是ServiceMethod)持有了Retrofit实例,CallAdapter实例,responseConverter 反序列工具实例。

//ServiceMethod构建方法,参数是构造器
ServiceMethod(Builder<T> builder) {
          this.callFactory = builder.retrofit.callFactory();//持有CallFactory实例
          this.callAdapter = builder.callAdapter;            //持有CallAdapter实例
          this.baseUrl = builder.retrofit.baseUrl();          //持有BaseUrl
          this.responseConverter = builder.responseConverter;//持有反序列工具
          ....注解相关
}

至此,ServiceMethod实例创建完毕,ServiceMethod变相的将各模块组装在一起。


问题四:OkHttpCall是什么?

</br>
先说两个概念:

interface okhttp3.Call{
       enqueue(Callback responseCallback);
       execute();
       request();
       isExecuted();
       isCanceled();
       cancel();
}    

interface retrofit2.Call{
       同上;
       clone();
}        

1,retrofit2.Call与okhttp3.Call区别就是多了个clone方法,retrofit2.Call需要clone,才能再次使用。
2,OkHttpCall 实现了retrofit2.Call。
3,CallFactory创建的是okhttp3.Call实例,OkHttpClient实现了okhttp3.Call。
WTF??看代码。

(以下省略适配、优化等细节代码)

//直接调用构造方法
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
OkHttpCall(ServiceMethod<T> serviceMethod, Object[] args) {
       this.serviceMethod = serviceMethod;  //持有了ServiceMethod实例
       this.args = args;//注解相关
}

OkHttpCall持有serviceMethod实例,就这样。但OkHttpCall 实现了retrofit2.Call,有必要看一下enqueue(Callback responseCallback);execute();

//外部传入callBack,结果回调
enqueue(final retrofit2.Callback<T> outCallback){
        //Retrofit NetWork模块实际使用的还是okhttp3.Call,retrofit2.Call只是对外放出的包装
        okhttp3.Call call = createRawCall(){
                //Retrofit 默认callFactory为OkHttpClient
                return serviceMethod.callFactory.newCall(request);
        };
        //利用okhttp3.Call发送请求,并传入新的CallBack();
        call.enqueue(
                new okhttp3.Callback() {
                        //成功
                        onResponse(okhttp3.Response rawResponse){
                            //parseResponse(rawResponse)是将请求结果反序列,内部调用ServiceMethod中的responseConverter,也就是配置里的反序列化工具生成JavaBean。
                            rawResponse = parseResponse(rawResponse)
                            //将反序列化后的JavaBean传给前台
                            outCallback.onResponse(rawResponse);
                        }
                        //失败
                        onFailure(Throwable e){
                            //将错误信息传给前台
                            outCallback.onFailure(e);
                        }
                }
        )
}
execute(){

        ...与enqueue大致相同, 也是利用CallFactory生成okhttp3.Call,调用okhttp3.Call.execute()

}

so:

1,OkHttpCall实现Retrofit.Call接口
2,CallFactory生成的Call对象为Okhttp3.Call接口
3,OkHttpCall持有CallFactory生成的Call对象
4,OkHttpCall在enqueue,execute方法中实际调用的是CallFactory生成的Call对象发送请求,OkHttpCall本身并没有NetWork的功能
5,所以,OkHttpCall只是适配器,或者说包装器,外部使用Retrofit.Call,Retrofit.Call内部使用Okhttp3.Call,Retrofit.Call与Okhttp3.Call之间,由OkHttpCall调度
6,OkHttpCall实现Retrofit.Call接口,与外部来说,无需关心NetWork到底是如何发送的


问题五:

serviceMethod.callAdapter.adapt(okHttpCall)是?

</br>
先回头撸一下

        mRetrofit
        //返回代理对象
        .create(RetorfitInterfaces.UserInfoServer.class)
        //serviceMethod.callAdapter.adapt(okHttpCall)返回retrofit2.Call对象
        .sendPost(userId)
        //调用返回的retrofit2.Call的enqueue方法
        .enqueue(call);

没毛病。

serviceMethod.callAdapter由Retrofit.CallAdapterFactory创建(上面源码有提到)。 而CallAdapterFactory可由外部配置,默认ExecutorCallAdapterFactory。

(以下省略适配、优化等细节代码)

//默认ExecutorCallAdapterFactory.adapt,创建返回了ExecutorCallbackCall实例
@Override public <R> Call<R> adapt(Call<R> call) {
        //call就是okHttpCall
       return new ExecutorCallbackCall<>(callbackExecutor, call);
}

//看看ExecutorCallbackCall又是什么,一个 Retrofit2.Call<T>实现类,
class ExecutorCallbackCall<T>implements Retrofit2.Call<T>{

        //构造函数,callbackExecutor配置中的线程池,delegate就是okHttpCall
        ExecutorCallbackCall(Executor callbackExecutor, retrofit2.Call<T> delegate) {                this.callbackExecutor = callbackExecutor;                this.delegate = delegate;        }
        
         //Retrofit2.Call<T>接口中的方法,发送异步请求,参数outCallBack是外部传入的回调接口
         enqueue(final Callback<T> outCallback){
                //利用delegate,其实就是okHttpCall发送请求,又是包装new Callback()
                delegate.enqueue(new Callback<T>() {
                    //成功
                     onResponse(Call<T> call, final Response<T> response) {
                            //线程调度
                             callbackExecutor.execute(new Runnable() {
                                    public void run() {
                                    //传给前台
                                      outCallBack.onResponse(
                                              ExecutorCallbackCall.this, response
                                      );
                                    }
                              }
                          }
                    //失败
                      onFailure(Call<T> call, final Throwable t){
                            //线程调度
                            callbackExecutor.execute(new Runnable() {
                                public void run() {
                                    outCallBack.onFailure(ExecutorCallbackCall.this, t);
                                }
                            });
                      }
            );
        }
         // ****Retrofit2.Call<T>接口中的方法,**发送同步请求**
        Response<T> execute(){
                    //delegate 就是okHttpCall
                     return delegate.execute();
        }
}

1,serviceMethod.callAdapter.adapt(okHttpCall)返回Retrofit2.Call实例,默认ExecutorCallbackCall
2,ExecutorCallbackCall实例中持有okHttpCall的实例
3,ExecutorCallbackCall实例中的enqueue,execute方法,方法中实际操作的还是OkHttpCall对应的方法。
4,ExecutorCallbackCall将请求结果通过制定线程(配置中的CallbackExecutor)发送到前台


问题六:CallFactory、okHttpCall、CallAdapter之间的关系?

</br>
从上向下的包装关系,,类似装饰模式:
** 外部调用**
** CallAdapterFactory.CallAdapter.Retrofit.Call**
** 包装**
okHttpCall.Retrofit.Call
** 包装**
CallFactory.okhttp3.Call

                      外部调用                                 
|---------------------------------------------------|
|              CallAdapter.Retrofit.Call            |
|     |---------------------------------------|     |
|     |        okHttpCall.Retrofit.Call       |     |
|     |     -----------------------------     |     |
|     |     |  CallFactory.okhttp3.Call |     |     |
|     |     -----------------------------     |     |
|     |                                       |     |
|     |---------------------------------------|     |
|                                                   |
|---------------------------------------------------|

CallFactory.okhttp3.Call面向发送请求,不关心结果处理
CallAdapterFactory.CallAdapter.Retrofit.Call面向返回结果,不关心发送
OkHttpCall.Retrofit.Call作为中间件,将两者联系起来
**外部实际调用的是CallAdapter生成的Retrofit.Call **

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,761评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,953评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,998评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,248评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,130评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,145评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,550评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,236评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,510评论 1 291
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,601评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,376评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,247评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,613评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,911评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,191评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,532评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,739评论 2 335

推荐阅读更多精彩内容