从OKHttp源码中看责任链模式

上篇文章简单理解责任链模式只做了Demo,这篇文章就结合OKHttp的框架来具体看看责任链模式,没看过上篇文章的建议可以看看,尤其是第四点优化代码那一块。

一个框架中往往会涉及到很多的设计模式,在OKHttp中用到责任链模式的是拦截器Interceptor,因为只是对责任链模式的源码分析,所有我会省略掉那些影响我们看源码的部分。

一、OkHttp框架中的Interceptor是如何使用责任链模式的

1、OKHttp的一个简单应用入口
    @Test
    public void test(){
        try{
            OkHttpClient client = new OkHttpClient();
            Request request = new Request.Builder()
                    .url("http://www.baidu.com/")
                    .build();
            Response response = client.newCall(request).execute();
            if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
            System.out.println(response.body().string());
        }catch (Exception e){
        }
    }
2、关键性源码分析
client.newCall(request),实例化了一个RealCall
 @Override public Call newCall(Request request) {
    return new RealCall(this, request, false /* for web socket */);
  }
client.newCall(request).execute() ,直接看RealCall中的execute()方法
  @Override public Response execute() throws IOException {
      ...
      Response result = getResponseWithInterceptorChain();
      ...
getResponseWithInterceptorChain(),执行拦截器
  • 责任链模式的Client
 Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
   //第一步:把对应的五个拦截器都放入到interceptors List中
    interceptors.addAll(client.interceptors());
    interceptors.add(retryAndFollowUpInterceptor);
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    interceptors.add(new CacheInterceptor(client.internalCache()));
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {
      interceptors.addAll(client.networkInterceptors());
    }
    interceptors.add(new CallServerInterceptor(forWebSocket));
    //第二步:把所有的具体处理者链接起来
    Interceptor.Chain chain = new RealInterceptorChain(
        interceptors, null, null, null, 0, originalRequest);
    //第三步:开始处理
    return chain.proceed(originalRequest);
  }

上面的代码和下面的这个截图是不是一样的(有不懂的童鞋,请看上篇简单理解责任链模式)


简单理解责任链模式4-Client
  • 真实的链接类
public final class RealInterceptorChain implements Interceptor.Chain {
  private final List<Interceptor> interceptors;
  private final int index;
  ...

  public RealInterceptorChain(List<Interceptor> interceptors, int index) {
    this.interceptors = interceptors;
    this.index = index;
  }

  public Response proceed(...) {
    if (index >= interceptors.size()) throw new AssertionError();
    ...
    // Call the next interceptor in the chain.
    RealInterceptorChain next = new RealInterceptorChain(
        interceptors, index + 1);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);
    ....
    return response;
  }
}

源码中index的值是从构造方法中传入的,追溯上去,可以看到初始化的index值传入的是0


简单理解责任链模式4-链接类
  • 具体的处理者(有5个)
public final class RetryAndFollowUpInterceptor implements Interceptor {
  ......
  @Override 
  public Response intercept(Chain chain) {
     ....
     response = ((RealInterceptorChain) chain).proceed(request, streamAllocation,     null, null);
     .....
    }
}
public final class BridgeInterceptor implements Interceptor {
   @Override 
   public Response intercept(Chain chain) throws IOException {
      ......
      Response networkResponse = chain.proceed(requestBuilder.build());
      .......
    }
}
public final class CacheInterceptor implements Interceptor {
   @Override 
   public Response intercept(Chain chain) throws IOException {
      ......
    networkResponse = chain.proceed(networkRequest);
      .......
    }
}
public final class ConnectInterceptor implements Interceptor {
    @Override
  public Response intercept(Chain chain) throws IOException {
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    ...
    return realChain.proceed(request, streamAllocation, httpCodec, connection);
  }
}
/** This is the last interceptor in the chain. It makes a network call to the server. */
public final class CallServerInterceptor implements Interceptor {
    @Override 
    public Response intercept(Chain chain) throws IOException {
      .....
     //类上有注释,这是链上的最后一个拦截器,所以就没调用proceed()了
    }
}

对比下,下面是简单的一个demo,上面是实际项目中的应用


简单理解责任链模式4-具体的处理者
  • 抽象处理者
public interface Interceptor {
  Response intercept(Chain chain) throws IOException;

  interface Chain {
    Request request();
    //链头的具体处理者
    Response proceed(Request request) throws IOException;

    Connection connection();
  }
}

1)在责任链模式的概念中把抽象处理类都是定义成abstract类,在OKHttp的实际应用中我们看到是定义成interface的
2)demo和实际对比,发现实际中把链头的具体处理者定义成一个接口的,让RealInterceptorChain去实现这个接口

public final class RealInterceptorChain implements Interceptor.Chain {
      @Override
      public Response proceed(Request request) throws IOException {
          return proceed(request, streamAllocation, httpCodec, connection);
      }

      public Response proceed(....) throws IOException {
          // Call the next interceptor in the chain.
          RealInterceptorChain next = new RealInterceptorChain(
          interceptors, streamAllocation, httpCodec, connection, index + 1, request);
          Interceptor interceptor = interceptors.get(index);
          //这里调用抽象接口自己的抽象方法
          Response response = interceptor.intercept(next);
          return response;
       }
    
}
简单理解责任链模式4-抽象处理者
3、OKHttp责任链模式的结构图

(第一次画这个图,折腾了好久,尤其是Interceptor和Chain之间的关系,我用了一个关联,不知道到底对不对,有问题的话,请帮忙指出,好修正,谢谢!)

OKHttp责任链模式.png
3、OKHttp实现原理图

从参考文档中的博主哪儿借用一张原理图,懒得自己去画了


原理图
参考文档

OKHttp中的责任链模式
总结中说到哪些著名的框架用到了责任链模式

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

推荐阅读更多精彩内容

  • 流程分析 我们从一个简单的 HTTP 请求开始: 上面的代码将会发起两个简单的 HTTP 请求,请求流程如下图所示...
    张可_阅读 872评论 0 2
  • 这段时间老李的新公司要更换网络层,知道现在主流网络层的模式是RxJava+Retrofit+OKHttp,所以老李...
    隔壁老李头阅读 32,615评论 51 405
  • OkHttp源码的samples的简单使用的示例: public static void main(String....
    _warren阅读 714评论 0 1
  • 娘家侄子生了儿子,八斤四两的大胖小子,今天中午吃喜酒。 一去到,家里家外都是亲戚朋友,见到大侄子就拉着我上二楼看胖...
    如风细语阅读 101评论 0 2
  • 符号 $\vec{v}_{\text{大地对男生}}$ 知识点 相对运动的矢量式 作图法 表达题 今有风相对大地以...
    我爱wuli阅读 205评论 0 0