OkHttp源码分析(一)

OkHttpClient

1.OkHttpClient应该创建一个单例,方便所有HTTP请求重用。 这是因为每个客户端都拥有自己的连接池和线程池, 重用这些连接和线程可以减少延迟并节省内存。 相反,为每个请求创建OkHttpClient会浪费空闲池中的资源。
实例化对象两种方式:

// The singleton HTTP client.
public final OkHttpClient client = new OkHttpClient();
// The singleton HTTP client.
public final OkHttpClient client = new OkHttpClient.Builder()
    .addInterceptor(new HttpLoggingInterceptor())
    .cache(new Cache(cacheDir, cacheSize))
    .build();

2.通过newBuilder() 方法自定义OkHttpClient实例。使用构建器提供的方法指定具体的配置项。

OkHttpClient eagerClient = client.newBuilder()
    .readTimeout(500, TimeUnit.MILLISECONDS)
    .build();
Response response = eagerClient.newCall(request).execute();

3.空闲状态下,线程池和连接池中的线程和连接将自动释放。但是,如果你的应用程序需要主动释放无用的资源,可以使用shutdown()关闭调度执行器的服务。 这也将导致后续的调用被拒绝。

client.dispatcher().executorService().shutdown();

evictAll()清除连接池。 请注意,连接池的守护程序线程可能不会立即退出。

client.connectionPool().evictAll();

如果您的客户端有缓存,请调用close()。 请注意,针对关闭的缓存创建调用是一个错误,这样做将导致调用崩溃。

client.cache().close();

OkHttp为HTTP / 2连接使用了守护线程。 如果它们保持空闲,将自动退出。

ConnectionSpec

指定socket 连接的配置。针对https:的URL包含了密码套件和TLS来加密连接。只有在SSL套接字中启用了TLS连接规范中配置的TLS版本才能使用。 例如,如果SSL套接字没有启用TLS 1.3,即使连接规范中存在TLS也不会使用。 同样的策略也适用于密码套件。使用ConnectionSpec.Builder.allEnabledTlsVersions()ConnectionSpec.Builder.allEnabledCipherSuites将所有功能选择推迟到底层SSL套接字。

ConnectionPool

管理HTTP和HTTP / 2连接的重用以减少网络延迟。共享相同Address对象的HTTP请求可能共享一个Connection对象。该类使用“保持连接开启”的策略以供后续使用。

Call / RealCall

Call是一个已准备执行的请求。可以被取消。由于此对象表示单个请求/响应对(流),因此无法执行两次。【接口】

public interface Call extends Cloneable {
  Request request();
  Response execute() throws IOException;
  void enqueue(Callback responseCallback);
  void cancel();
  boolean isExecuted();
  boolean isCanceled();
  Call clone();
  interface Factory {
    Call newCall(Request request);
  }
}

RealCall是Call的实现类,持有OkHttpClient和Request的引用,复写了Call的两个关键方法execute()和enqueue(Callback responseCallback)。前者为同步调用,后者为异步调用

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

  @Override 
  public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

execute()辗转调用了dispather.execute方法,仅仅是为了将Request添加到一个请求集合中。

RealInterceptorChain

一个具体的拦截器链,其中携带整个拦截器链:所有应用拦截器,OkHttp核心,所有网络拦截器,最后是网络调用者。

链中的拦截器通过调用intercept方法执行具体操作。

  • RetryAndFollowUpInterceptor拦截器作用:从故障中恢复,并根据需要遵循重定向。
    此拦截器实例化StreamAllocation
  • BridgeInterceptor拦截器作用:从应用程序到网络的桥梁。首先,它根据用户请求构建网络请求,然后它继续调用网络。最后,它从网络响应中构建用户响应。
    处理请求体body和请求头header的配置信息,cookie等
  • CacheInterceptor拦截器作用:从缓存中请求数据,写响应数据到缓存中
  • ConnectInterceptor拦截器作用:
    打开与目标服务器的连接,并进入下一个拦截器。
    1.实例化HttpCodec:对HTTP请求编码,对HTTP响应解码。
    2.实例化RealConnection
  • CallServerInterceptor拦截器作用:这是链中的最后一个拦截器。它对服务器进行网络调用。

场景图
采用自增递归(recursive)调用Chain.process()
这里写图片描述

StreamAllocation

该类协调三个实体之间的关系:
Connections:到远程服务器的物理Socket连接。这些建立可能很慢,所以有必要能够取消当前的连接。
Streams:在连接上分层的逻辑HTTP请求/响应对。每个连接都有自己的分配限制,它定义了连接可以携带多少个并发流。 HTTP / 1.x连接一次可以携带1个流,HTTP / 2通常携带多个。
Calls:流的逻辑序列,通常是初始请求及其后续请求。HTTP请求任务封装。

StreamAllocation: 用来控制Connections/Streams的资源分配与释放

  • 选择路线与自动重连(RouteSelector)
    此步骤用于获取socket的ip与端口
  • 连接socket链路(RealConnection)
    此步骤可以进行TCP连接(三次握手)
  • 释放socket链路(release)

Dispatcher

执行异步请求时的策略。
每个调度程序都使用ExecutorService在内部运行调用。 如果您提供自己的执行程序,它应该能够并发运行配置的最大调用数。
默认使用了线程池执行器ThreadPoolExecutor,最大请求数64个.

private int maxRequests = 64;//最大请求数
private int maxRequestsPerHost = 5;//每个主机最大请求数
private Runnable idleCallback;//任务执行完毕,空闲的Runnable

/** Executes calls. Created lazily. */
private ExecutorService executorService;//线程池

/** Ready async calls in the order they'll be run. */
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();//缓存队列,当runningAsyncCalls满后,会添加到此队列

/** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();//正在运行的任务,仅仅是用来引用正在运行的任务以判断并发量,注意它并不是消费者缓存

/** Running synchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();//同步调用集合

Dispatcher有两个构造函数,可以使用自己设定线程池,如果没有设定线程池则会在请求网络前自己创建线程池。

public Dispatcher(ExecutorService executorService) {
  this.executorService = executorService;
}

public Dispatcher() {
}

public synchronized ExecutorService executorService() {
  if (executorService == null) {
    executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
        new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
  }
  return executorService;
}

异步调用方法,RealCall.enqueue

@Override 
public void enqueue(Callback responseCallback) {
  synchronized (this) {
    if (executed) throw new IllegalStateException("Already Executed");
    executed = true;
  }
  captureCallStackTrace();
  client.dispatcher().enqueue(new AsyncCall(responseCallback));
}

其中AsyncCall是一个Runnable,添加到Deque runningAsyncCalls集合中,由线程池负责执行。

Dispatcher.enqueue()

synchronized void enqueue(AsyncCall call) {
  if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
    runningAsyncCalls.add(call);
    executorService().execute(call);
  } else {
    readyAsyncCalls.add(call);
  }
}

执行的是AsyncCall这个Runnable,即run方法,在这里转化为execute方法了

@Override 
protected void execute() {
  boolean signalledCallback = false;
  try {
    //通过拦截器链获取响应信息
    Response response = getResponseWithInterceptorChain();
    if (retryAndFollowUpInterceptor.isCanceled()) {
      signalledCallback = true;
      responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
    } else {
      signalledCallback = true;
      responseCallback.onResponse(RealCall.this, response);
    }
  } catch (IOException e) {
    if (signalledCallback) {
      // Do not signal the callback twice!
      Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
    } else {
      responseCallback.onFailure(RealCall.this, e);
    }
  } finally {
    client.dispatcher().finished(this);
  }
}

知识点:
根据可变参数,返回不可修改的集合

/** Returns an immutable list containing {@code elements}. */
  public static <T> List<T> immutableList(T... elements) {
    return Collections.unmodifiableList(Arrays.asList(elements.clone()));
  }

OkHttp3架构分析

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青菜小王子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值