OkHttp3 源码解析

参考地址

调用方式

同步调用

@Override  public  Response execute() throws IOException {
  synchronized (this) {
    if (executed) throw new IllegalStateException("Already Executed");
    executed = true;
  }
  try {
    client.dispatcher().executed(this);
    Response result = getResponseWithInterceptorChain(false);
    if (result == null) throw new IOException("Canceled");
    return result;
  } finally {
    client.dispatcher().finished(this);
  }
}

异步调用

void enqueue(Callback responseCallback, boolean forWebSocket) {
  synchronized (this) {
    if (executed) throw new IllegalStateException("Already Executed");
    executed = true;
  }
  client.dispatcher().enqueue(new AsyncCall(responseCallback, forWebSocket));
}

总体架构

image

接口层

OKHttpClient 全局维护一个实例,对全局OkHttp 进行设置

Call 表示一次请求执行,分为同步的ReallCall及AsyncCall

协议层

处理特定的协议逻辑,OkHttp支持Http1/Http2/WebSocket协议

连接层

管理网络连接,网络连接请求,服务返回

  • RealConnection 描述一个Socket的连接请求。ConnectionPool 缓存了多个Connection。
  • StreamAllocation表示一次全新的网络请求(一个Call请求可能包含有多个StreamAllocation ,比如重定向)

缓存层

管理本地缓存,当本地有可用缓存时,直接采用本地的以节约流量

I/O层

表示数据的实际读写,采用OKIO

Iterceptor 拦截器层

拦截器逻辑

首先由getResponseWithInterceptorChain 把系统及自定义的拦截器传入
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 (!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);
  }
调用 RealInterceptorChain 的process 方法轮训每个拦截器
public final class RealInterceptorChain implements Interceptor.Chain {


  public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      RealConnection connection) 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;
  }
}

RetryAndFollowUpInterceptor

  • 访问失败后进行重试
  • 对服务器要求重定向的情况下进行连接复用

BridgeIterceptor

  • 设置内容长度及类型
  • 设置cookie
  • 设置gzip并在获取response 后进行释放
  • 设置其他报头

CacheInterceptor

  • 增加符合网络要求的cache
  • 更新服务器的最新cache
  • 当前cache失效则输出cache

ConnectInterceptor

CallServerInterceptor

整体流程

image

任务队列

同步

直接执行

异步队列
client.newCall(request).enqueue();
// 具体执行
synchronized void enqueue(AsyncCall call) {
  if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      //添加正在运行的请求
    runningAsyncCalls.add(call);
       //线程池执行请求
    executorService().execute(call);
  } else {
      //添加到缓存队列排队等待
    readyAsyncCalls.add(call);
  }
}
  • 若线程数未达到最大请求则通过线程池直接执行
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
          new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
  • 若线程数达到最大请求则加入等待队列,当其他线程执行完成后调用client.dispatcher().finished(this); 来继续执行等待的队列

缓存

Http 缓存策略

  • Expires 超时时间,当访问服务器时比较超时时间,若未超过直接返回缓存结果
  • Cache-Control 表示当前资源的有效期
  • 条件GET请求
客户端第一次请求时,服务器返回:

Last-Modified: Tue, 12 Jan 2016 09:31:27 GMT
当客户端二次请求时,可以头部加上如下header:

If-Modified-Since: Tue, 12 Jan 2016 09:31:27 GMT
如果当前资源没有被二次修改,服务器返回304告知客户端直接复用本地缓存。
  • Etag
ETag是对资源文件的一种摘要,可以通过ETag值来判断文件是否有修改。当客户端第一次请求某资源时,服务器返回:

ETag: "5694c7ef-24dc"
客户端再次请求时,可在头部加上如下域:

If-None-Match: "5694c7ef-24dc"
如果文件并未改变,则服务器返回304告知客户端可以复用本地缓存。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值