谈谈 OkHttp 对责任链模式的巧妙应用

1 概述

OkHttp 的拦截器就是基于责任链模式,每个节点有自己的职责,同时可以选择是否把任务传递给下一个环节

整个过程像工厂流水线一样,传递用户发起的请求 Request,每一个拦截器完成相应的功能,从失败重试和重定向实现、请求头的修改和Cookie 的处理,缓存的处理,建立 TCP 和 SSH 连接,发送 Request 和读取 Response,每一个环节由专门的 Interceptor 负责。

2 类和接口

2.1 Inteceptor

主要方法 Intercept。会传递一个 Chain 对象过来,可以在 Chain 在执行 proceed 的前后添加代码。

2.2 Chain

主要方法 proceed。OkHttp 的唯一实现类是 RealInterceptorChain。内部维护了所有要执行的拦截器列表,在 proceed 内部会唤醒下一个 Interceptor ,调用 intercept 来进行下一步:

public Response proceed(Request request, StreamAllocation streamAllocation, HttpStream httpStream,
    Connection connection) throws IOException {
  ...
  RealInterceptorChain next = new RealInterceptorChain(
      interceptors, streamAllocation, httpStream, connection, index + 1, request);
  Interceptor interceptor = interceptors.get(index);
  Response response = interceptor.intercept(next);
  ...
  return response;
}

该类的主要成员有:

  • List ,所有拦截器列表。

  • StreamAllocation,用来协调 Connection,Stream 和 Calls 的关系。封装了网络连接创建的一些策略。比如使用 RouteSelector 和 RouteDatabase 在建联失败后的多 IP 路由的选择;HttpStream 流的创建;Connection 的创建和使用 ConnectionPool 进行连接复用等。

  • HttpStream,网络数据流的抽象,因为不同的 HTTP 协议,流的传输方式不一样,有两个实现 Http1xStream 和 Http2xStream。主要的职责为写入 Request 请求,并且读取 Response 响应。

  • Connection,网络连接的抽象,唯一实现 RealConnection。主要用来管理连接用的 Socket。RealConnection 调用 connect 来进行Socket 连接。

  • Request,请求体的抽象,包括方法、请求头、请求体。

RealInterceptorChain 对 proceed 进行了扩展,在拦截器链式传递的过程中增加了这些对象的传递。所以执行拦截器的时候,启动下一个拦截器的前,可以对这些对象进行创建或者修改,然后再传递给下一个拦截器,或者调用这些对象完成相应的功能。比如在 RetryAndFollowUpInterceptor 会创建 StreamAllocation,在 BridgeInterceptor 会修改 Request 的请求头,在 ConnectInterceptor 会调用 StreamAllocation 的 newStream 方法建立连接等等。

3 基本流程

Call 抽象了一次请求,唯一实现类为 RealCall。

当我们调用 call.execute 发起请求后,整个请求的流程发生在下面的方法中:

  private Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List interceptors = new ArrayList<>();
    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 (!retryAndFollowUpInterceptor.isForWebSocket()) {
      interceptors.addAll(client.networkInterceptors());
    }
    interceptors.add(new CallServerInterceptor(
        retryAndFollowUpInterceptor.isForWebSocket()));

    Interceptor.Chain chain = new RealInterceptorChain(
        interceptors, null, null, null, 0, originalRequest);
    return chain.proceed(originalRequest);
  }

通过一系列拦截器进行链式操作,一环接一环,每个拦截器负责单独的任务,环环相扣完成整个请求:

  • RetryAndFollowUpInterceptor,用来实现连接失败的重试和重定向。

  • BridgeInterceptor,用来修改请求和响应的 header 信息。

  • CacheInterceptor,用来实现响应缓存。比如获取到的 Response 带有 Date,Expires,Last-Modified,Etag 等 header,表示该 Response 可以缓存一定的时间,下次请求就可以不需要发往服务端,直接拿缓存的。

  • ConnectInterceptor,用来打开到服务端的连接。其实是调用了 StreamAllocation 的newStream 方法来打开连接的。建联的 TCP 握手,TLS 握手都发生该阶段。过了这个阶段,和服务端的 socket 连接打通。

  • CallServerInterceptor,用来发起请求并且得到响应。上一个阶段已经握手成功,HttpStream 流已经打开,所以这个阶段把 Request 的请求信息传入流中,并且从流中读取数据封装成 Response 返回。

谈谈 OkHttp 对责任链模式的巧妙应用_第1张图片
请求的流程

你可能感兴趣的:(谈谈 OkHttp 对责任链模式的巧妙应用)