OkHttp的拦截器机制分析

来源:互联网 发布:淘宝卖家地址是真的吗 编辑:程序博客网 时间:2024/06/05 05:27

1 概述

AOP 编程。每次的 proceed 是执行点,可以在执行点的前面和后面添加需要的业务逻辑。比如打打日志,失败重试,添加缓存等等。

拦截器就是基于责任链模式,每个节点有自己的职责,同时可以选择是否把任务传递给下一个环节拦截器的设计,可以像工厂流水线一样,传递用户发起的请求 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<Interceptor>

    所有拦截器列表;

  • 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<Interceptor> 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 返回;

原创粉丝点击