分析OKHttp

整体架构

Interface——接口层:接受网络访问请求

Protocol——协议层:处理协议逻辑

Connection——连接层:管理网络连接,发送新的请求,接收服务器访问

Cache——缓存层:管理本地缓存

I/O——I/O层:实际数据读写实现

Inteceptor——拦截器层:拦截网络访问,插入拦截逻辑

官方文档是这样描述OkHttp

  • OkHttp is an HTTP client that’s efficient by default:
  • HTTP/2 support allows all requests to the same host to share a socket.
  • Connection pooling reduces request latency (if HTTP/2 isn’t available).
  • Transparent GZIP shrinks download sizes.
  • Response caching avoids the network completely for repeat requests.

OkHttp是一个高效的HTTP客户端,拥有以下特性:

  • HTTP/2支持对同一主机的所有请求共享套接字。
  • 使用连接池减少请求延迟(如果HTTP/2不可用)。
  • 透明GZIP减少下载大小。
  • 响应缓存可以完全避免网络重复请求。

核心类

  1. okhttp3.OkHttpClient:全局配置与网络操作入口

  2. okhttp3.Request:一次网络请求的url、body、header等

  3. okhttp3.Response:一次网络请求的响应

  4. okhttp3.RealCall:代表一个OkHttp封装的实际网络操作实例

  5. okhttp3.Dispatcher:操作okhttp3.RealCall,连接池,异步请求线程池封装

  6. okhttp3.Callback:异步请求的callback

  7. okhttp3.RealCall.AsyncCall#AsyncCall:对于okhttp3.Callback的封装,继承NamedRunnable实现Runnable接口,是OkHttp实现异步网络请求的重要组成部分

  8. okhttp3.internal.connection.Transmitter:

  9. okhttp3.internal.connection.Exchange:

  10. okhttp3.internal.Internal:

1.1 调用

OkHttp提供了两种调用方式:

  • 同步调用

  • 异步调用

1.1.1 同步调用

okhttp3.OkHttpClient#newCall(Request request)# execute() -> okhttp3.RealCall#execute

public Response execute() throws IOException {

        synchronized(this) {

            if (this.executed) {

                throw new IllegalStateException("Already Executed");

            }



            this.executed = true;

        }



        this.transmitter.timeoutEnter();

        this.transmitter.callStart();



        Response var1;

        try {

            this.client.dispatcher().executed(this);

            var1 = this.getResponseWithInterceptorChain();

        } finally {

            this.client.dispatcher().finished(this);

        }

        return var1;

    }
  1. 加锁,打上标记位(this.executed = true),避免多次调用RealCall#execute
  2. 将RealCall加入到同步队列
    3.this.client.dispatcher().executed(this)
    4.OkHttpClient.Dispatcher.runningSyncCalls.add(call)
    5.调用getResponseWithInterceptorChain实际执行HTTP请求
  3. 从同步队列中删除
  4. this.client.dispatcher().finished
    8.OkHttpClient.Dispatcher.runningSyncCalls.remove(call)
1.1.2 异步调用

okhttp3.OkHttpClient#newCall(Request request)# enqueue (Callback ) responseCallback) -> okhttp3.RealCall#enqueue

  1. [endif]加锁,打上标记位(this.executed = true),避免多次调用RealCall#execute

  2. 将Callback封装成AsyncCall,放入到异步执行队列中

    1. readyAsyncCalls#add
    2. AsyncCall继承NamedRunnable,也就实现了Runnable接口
    3. 调用Dispatcher#promoteAndExecute

2 OkHttp异步网络请求的实现

从1.1.2中已经有一个简单的异步请求分析,一个异步请求(AsyncCall)的AsyncCall#execute方法最终会被调用,在执行拦截器Chain后得到Response。

3 拦截器

   从第2节中,已经可以看到发起一个请求的重要代码是
   AsyncCall#execute(异步) OR RealCall#execute(同步),其中的核心是

1.获取并执行拦截器Chain得到Response- getResponseWithInterceptorChain

2.通知分发器任务完成- client.dispatcher().finished

  在不考虑异常的情况下,OkHttp发起一个HTTP请求,实际的网络操作都在getResponseWithInterceptorChain方法中体现。

3.1 构造拦截器链

Response getResponseWithInterceptorChain() throws IOException {

    // Build a full stack of interceptors.

    List interceptors = new ArrayList<>();

    interceptors.addAll(client.interceptors());

    interceptors.add(new RetryAndFollowUpInterceptor(client));

    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, transmitter, null, 0,

        originalRequest, this, client.connectTimeoutMillis(),

        client.readTimeoutMillis(), client.writeTimeoutMillis());

    Response response = chain.proceed(originalRequest);

…

  }

其中主要逻辑分为两部分

1.创建一系列的拦截器,包括系统内置与用户自定义的拦截器

2.创建RealInterceptorChain,并执行proceed方法得到Response

拦截器顺序是

  1. 自定义拦截器(interceptors)

  2. RetryAndFollowUpInterceptor

  3. BridgeInterceptor

  4. CacheInterceptor

  5. ConnectInterceptor

  6. 自定义网络拦截器(networkInterceptors)

  7. CallServerInterceptor

那么RealInterceptorChain#proceed做了什么呢?

// Call the next interceptor in the chain.

RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,index + 1, request, call, connectTimeout, readTimeout, writeTimeout);

Interceptor interceptor = interceptors.get(index);

Response response = interceptor.intercept(next);

return response;

可以看到主要也是两部分

  • 创建下一个RealInterceptorChain,指明下一个执行的拦截器索引为index + 1

  • 执行(调用intercept)索引为index的拦截器

接下来从系统内置第一个拦截器RetryAndFollowUpInterceptor为例,看看在intercept方法中做了什么。

从名字中我们可以看出,这个拦截器的主要作用应该是处理请求的重试与重定向。

3.2 内置拦截器责则

RetryAndFollowUpInterceptor
  • 在网络请求失败后进行重试

  • 当服务器返回当前请求需要进行重定向时直接发起新的请求,并在条件允许情况下复用当前连接

BridgeInterceptor
  • 设置内容长度、编码

  • 设置内容长度,内容编码

  • 添加cookie

  • 设置一些http head,例如User-Agent: okhttp/3.14.2; keep-Alive等、

CacheInterceptor

当网络请求有符合要求的Cache时直接返回Cache

当服务器返回内容有改变时更新当前cache

如果当前cache失效,删除

ConnectInterceptor
  • 负责找到一个合适的Connection。其中ExchangeCodec持有一个可用的Connection。

重点代码:

exchangeFinder->okhttp3.internal.connection.Transmitter#prepareToConnect->

由RetryAndFollowUpInterceptor触发

  ExchangeCodec codec = exchangeFinder.find(client, chain, doExtensiveHealthChecks);

  Exchange result = new Exchange(this, call, eventListener, exchangeFinder, codec);
CallServerInterceptor

负责向服务器发起真正的访问请求,并在接收到服务器返回后读取响应返回。

3.3 请求拦截链的整体流程

--TODO

4 任务队列(异步请求线程池)

在前面的分析中已经提及Dispatcher类是用于操作okhttp3.RealCall,对连接池,异步请求线程池封装。

与任务队列相关的字段:

readyAsyncCalls:待执行异步任务队列

runningAsyncCalls:运行中异步任务队列

runningSyncCalls:运行中同步任务队列

executorService:任务队列线程池

从代码可以看到,构建了一个线程池corePoolSize是0,最大线程数是Integer.MAX_VALUE,空闲时间是60秒,阻塞队列使用SynchronousQueue,这个阻塞队列不储存元素。

因此该线程池是来一个请求就会创建一个线程,当线程空闲60s后会被回收,由于corePoolSize是0,那么当60s没有新的请求,所有的线程都会给回收。

5 缓存策略

TO DO

6 连接池

在OkHttp中使用okhttp3.ConnectionPool来管理连接池,在okhttp3.ConnectionPool内部使用okhttp3.internal.connection.RealConnectionPool delegate来实际管理连接池。

okhttp3.internal.connection.RealConnectionPool

主要字段:

Executor executor:用于清除失效连接线程池

int maxIdleConnections:最大闲置连接数

long keepAliveDurationNs:keep alive时间

Runnable cleanupRunnable:清除失效连接

boolean cleanupRunning:put的时候设置为true,清除失效连接之后设置为false

Deque connections:产生的Connection

RouteDatabase routeDatabase:

主要方法:

int idleConnectionCount():统计idle的connection数

boolean transmitterAcquirePooledConnection:尝试复用一个Connection并关联上transmitter

void put(RealConnection connection):添加一个Connection,并触发cleanup线程

boolean connectionBecameIdle(RealConnection connection):当一个Connection空闲根据条件判断唤醒cleanup线程或者直接remove这个Connection

void evictAll():扫描并关闭所有空闲连接

long cleanup(long now):实际进行清除失效连接操作

int pruneAndGetAllocationCount():标记泄露的连接

void connectFailed():连接失败

相关类

okhttp3.internal.connection.RealConnection

封装物理连接

List>的引用计数(TransmitterReference)

okhttp3.internal.connection.Transmitter

okhttp3.internal.connection.RouteDatabase

用来记录连接失败的Route的黑名单,当连接失败的时候就会把失败的线路加进去

7 类分析

7.1 okhttp3.internal.connection.Transmitter

Bridge between OkHttp's application and network layers. This class exposes high-level application layer primitives: connections, requests, responses, and streams.

OkHttp应用和网络层的桥梁。这个类暴露高级应用层的原语:连接,请求,响应,流

附录

项目地址:https://github.com/square/okhttp

项目文档:https://github.com/square/okhttp/wiki

Easy OkHttp(对OkHttp的封装):https://gitee.com/yuanzizhenxin/easy-okhttp

源码分析(OkHttp 3.7):https://yq.aliyun.com/articles/78105

你可能感兴趣的:(分析OKHttp)