OkHttp源码学习笔记 (一) 主线流程源码分析

一、知识介绍:

1. 先说下OSI七层模型

应用层(指的是 http https rtmp)

表示层(如 数据加密解密/编码解码)

会话层(把 传输端口与接收端口建立会话)

传输层(这里就是他通过socket套接字抽象层 tcp长连接 udp非长连接)

网络层(通过IP查找目标主机 , 找到路径, 发送报包)

数据链路层(交换机)

物理层(物理传输 网线,把数据变成比特流 二进制数据传输)

 

2.在OSI之后转变衍生出TCP/IP四层模型

应用层(OSI中的 应用+表示+会话)

传输层

网络层

主机至网络层(OSI中的 数据链路+物理)

 

3.OkHttp的改造是针对哪一层?

实际上OkHttp框架并非直接使用应用层的来进行改造的框架,而是基于传输层的Socket对应用层的Http的封装改造.

 

4.Http协议概念

Http1.0  每发起一次请求, socket 请求->响应 三次握手, 断开则有四次挥手.

Http1.1  发起一次请求后, 客户端跟服务端进行连接, 会通过keeplive对connection连接进行长连接保持, 后续不断继续发起请求, 也只会有之前的一次"三次握手"操作, 直到断开 才会出现一次"四次挥手".   但是缺点是对服务器压力大.

 

5.Http Request请求分析

上面是Post的情况, 如果是get 就没有"请求体"和"请求体长度"和"请求体类型"

 

 

 

二、主线流程源码分析

OkHttp主要的几个类 OkHttpClient Request Response Call Callback

类介绍

OkHttpClient.java  采用构建者模式进行对象实例 , Builder是内部类, 内部存有预设参数 调度器 连接池等:

public static final class Builder {
  // 调度器
  Dispatcher dispatcher;
  @Nullable Proxy proxy;
  List<Protocol> protocols;
  List<ConnectionSpec> connectionSpecs;
  final List<Interceptor> interceptors = new ArrayList<>();
  final List<Interceptor> networkInterceptors = new ArrayList<>();
  EventListener.Factory eventListenerFactory;
  ProxySelector proxySelector;
  CookieJar cookieJar;
  @Nullable Cache cache;
  @Nullable InternalCache internalCache;
  SocketFactory socketFactory;
  @Nullable SSLSocketFactory sslSocketFactory;
  @Nullable CertificateChainCleaner certificateChainCleaner;
  HostnameVerifier hostnameVerifier;
  CertificatePinner certificatePinner;
  Authenticator proxyAuthenticator;
  Authenticator authenticator;
  ConnectionPool connectionPool;
  Dns dns;
  boolean followSslRedirects;
  boolean followRedirects;
  boolean retryOnConnectionFailure;
  int callTimeout;
  int connectTimeout;
  int readTimeout;
  int writeTimeout;
  int pingInterval;

  public Builder() {
    dispatcher = new Dispatcher();
    protocols = DEFAULT_PROTOCOLS;
    connectionSpecs = DEFAULT_CONNECTION_SPECS;
    eventListenerFactory = EventListener.factory(EventListener.NONE);
    proxySelector = ProxySelector.getDefault();
    if (proxySelector == null) {
      proxySelector = new NullProxySelector();
    }
    cookieJar = CookieJar.NO_COOKIES;
    socketFactory = SocketFactory.getDefault();
    hostnameVerifier = OkHostnameVerifier.INSTANCE;
    certificatePinner = CertificatePinner.DEFAULT;
    proxyAuthenticator = Authenticator.NONE;
    authenticator = Authenticator.NONE;
    connectionPool = new ConnectionPool();
    dns = Dns.SYSTEM;
    followSslRedirects = true;
    followRedirects = true;
    retryOnConnectionFailure = true;
    callTimeout = 0;
    connectTimeout = 10_000;
    readTimeout = 10_000;
    writeTimeout = 10_000;
    pingInterval = 0;
  }
}

 

Request.java  也是采用构建者模式, 存放如url header之类的信息

public static class Builder {
  @Nullable HttpUrl url;
  String method;
  Headers.Builder headers;
  @Nullable RequestBody body;
}

 

Call.java   其实是接口

public interface Call extends Cloneable {
  
  Request request();

  Response execute() throws IOException;

  void cancel();
  
  boolean isExecuted();

  boolean isCanceled();

  Timeout timeout();
 
  Call clone();

  interface Factory {
    Call newCall(Request request);
  }
}

 

CallBack.java 也是接口

public interface Callback {

  // 失败在这里
  void onFailure(Call call, IOException e);

  // 成功在这里
  void onResponse(Call call, Response response) throws IOException;
}

 

 

开始分析

在OkHttp, 创建Call实例实际上是通过OkHttpClient.java中的newCall方法来进行的

  @Override public Call newCall(Request request) {
    // 这里面实际上是用RealCall.java来进行操作的
    return RealCall.newRealCall(this, request, false /* for web socket */);
  }
final class RealCall implements Call {

  // 实例化RealCall对象
  static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    // Safely publish the Call instance to the EventListener.
    RealCall call = new RealCall(client, originalRequest, forWebSocket);
    call.transmitter = new Transmitter(client, call);
    return call;
  }

  // 同步请求
  @Override public Response execute() throws IOException {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    transmitter.timeoutEnter();
    transmitter.callStart();
    try {
      client.dispatcher().executed(this);
      return getResponseWithInterceptorChain();
    } finally {
      client.dispatcher().finished(this);
    }
  }

  // 异步请求
  @Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    transmitter.callStart();
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

}

上述代码中能看到, 返回call对象其实是在RealCall.java进行的, 而实际上这个RealCall 就是Call接口的实现类, 无论是同步请求方法execute 还是异步请求enqueue. 都在这实现类进行的.

 

现在看看异步请求的处理

在我们实际使用中, 做异步请求只需要走call的这个enqueue方法传入回调接口Callback即可.

现在我们来分析下enqueue做了什么

  @Override public void enqueue(Callback responseCallback) {
    // 在这里加一把锁,在锁里面判断 如果该call的请求已被执行过, 那么就会抛出异常
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    // 这个可以先不管
    transmitter.callStart();
    // 这里着重看
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

client.dispatcher() 就是从OkHttpClient中拿取dispatcher调度器. 而在前面也已经分析过dispatcher调度器其实就是在OkHttpClient通过构建者模式Builder()的时候, 已经被初始化了. 默认情况是直接new出来的.

换而言之 而真正执行enqueue方法的 其实是Dispatcher调度器, 而且我们原先的Callback对象还被一个叫AsyncCall的玩意给封装起来了. 注意好了, 这个AsyncCall其实是RealCall里面的一个内部类来着. 而AsyncCall是真正执行异步任务的, 待会再讲

我们可以先看看调度器的enqueue其实做了啥.

public final class Dispatcher {
  // 这里是调度器enqueue加入队列的真正实现
  void enqueue(AsyncCall call) {
    synchronized (this) {
      // 把AsyncCall添加到一个叫readyAsyncCalls的"就绪队列"中去
      readyAsyncCalls.add(call);

      // 这里面是跟webSocket相关的, 这次先不管他
      if (!call.get().forWebSocket) {
        AsyncCall existingCall = findExistingCallWithHost(call.host());
        if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
      }
    }
    // 在这里确认事件并开始执行
    promoteAndExecute();
  }

  /**
   * 这里大概的意思是把call任务 从ready就绪状态 改变为 running运行状态.并在一个线程池里面进行运行. 最终返回的东西是"调度器是否正在运行"
   * Promotes eligible calls from {@link #readyAsyncCalls} to {@link #runningAsyncCalls} and runs
   * them on the executor service. Must not be called with synchronization because executing calls
   * can call into user code.
   *
   * @return true if the dispatcher is currently running calls.
   */
  private boolean promoteAndExecute() {
    assert (!Thread.holdsLock(this));

    List<AsyncCall> executableCalls = new ArrayList<>();
    boolean isRunning;
    synchronized (this) {
      // 在这里对"就绪队列"进行遍历
      for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
        // 抽出下一个异步任务
        AsyncCall asyncCall = i.next();
        // 如果"运行队列"总数已经超过了最大请求值, 那就会终止循环
        if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
        // 如果该异步任务每个Host主机的请求大于最大请求值, 则本次循环终止
        if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity.

        // 前面都没问题,则表示可以继续往后走,移除掉"就绪队列"当前这位元素
        i.remove();
        // Host主机请求数自增
        asyncCall.callsPerHost().incrementAndGet();
        // 当前异步任务添加到"可执行队列"
        executableCalls.add(asyncCall);
        // 当前异步任务添加到"运行队列"
        runningAsyncCalls.add(asyncCall);
      }
      // 只要"运行队列"长度不为0 那么都记录"正在运行"
      isRunning = runningCallsCount() > 0;
    }

    // 从"可执行队列"里面进行遍历
    for (int i = 0, size = executableCalls.size(); i < size; i++) {
      AsyncCall asyncCall = executableCalls.get(i);
      // 先执行executorService(), 拿到线程池
      // 在线程池上进行真实请求
      asyncCall.executeOn(executorService());
    }

    return isRunning;
  }

  // 在这里创建/获取线程池
  public synchronized ExecutorService executorService() {
    if (executorService == null) {
      executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
          new SynchronousQueue<>(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;
  }


}

到了asyncCall.executeOn(executerService())这里后, 我们得知, 这里做了这么多事情, 其实就是为了弄一条"可执行队列"出来, 真正的运行 依然还得看AsyncCall, 前面留下的伏笔 现在来看看吧

final class RealCall implements Call {

  // 别忘了AsyncCall其实是RealCall里面的内部类, 继承的是NamedRunnable 而NameRunnable实现了Runnable.具体可以往下拉 拉到代码块的最后面, 有NamedRunnable的介绍
  final class AsyncCall extends NamedRunnable {
    // 这就是前面封装在AsyncCall里面的原装CallBack.
    private final Callback responseCallback;
    // 这个就是Host主机的请求数
    private volatile AtomicInteger callsPerHost = new AtomicInteger(0);

    AsyncCall(Callback responseCallback) {
      super("OkHttp %s", redactedUrl());
      this.responseCallback = responseCallback;
    }

    /**
     * 这里就是真正的异步任务处理方法了
     * Attempt to enqueue this async call on {@code executorService}. This will attempt to clean up
     * if the executor has been shut down by reporting the call as failed.
     */
    void executeOn(ExecutorService executorService) {
      assert (!Thread.holdsLock(client.dispatcher()));
      boolean success = false;
      try {
        // 在这里 用线程池来把"当前类"进行运行, 由于
        executorService.execute(this);
        // 如果一切顺利 标记为成功
        success = true;
      } catch (RejectedExecutionException e) {
        InterruptedIOException ioException = new InterruptedIOException("executor rejected");
        ioException.initCause(e);
        transmitter.noMoreExchanges(ioException);
        // 如果出了任何异常情况 那就会直接走callBack的失败接口回调方法.
        responseCallback.onFailure(RealCall.this, ioException);
      } finally {
        // 如果不顺利的话 那就会走调度器的结束.表示该call任务不再运作了.
        if (!success) {
          client.dispatcher().finished(this); // This call is no longer running!
        }
      }
    }


    // 这里真正执行
    @Override protected void execute() {
      // 这个仅仅是个标记, 标记为一旦发生异常, 是开发者造成的还是框架出问题
      boolean signalledCallback = false;
      transmitter.timeoutEnter();
      try {
        // 拿到响应消息, 这里是一个重点, 这里是责任链设计模式, 通过拦截器来获取响应信息
        Response response = getResponseWithInterceptorChain();
        signalledCallback = true;
        // 在这里进行成功回调
        responseCallback.onResponse(RealCall.this, response);
      } catch (IOException e) {
        if (signalledCallback) {
          // 如果是true的话, 那就会打印这句话, 表明是开发者写的代码有问题
          // Do not signal the callback twice!
          Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
        } else {
          // 走了这里 表明标记为false 表示是本框架请求异常了.
          // 在这里作失败回调
          responseCallback.onFailure(RealCall.this, e);
        }
      } catch (Throwable t) {
        cancel();
        if (!signalledCallback) {
          // 走到这里 表明标记为false,那就是真的是框架请求异常了.
          IOException canceledException = new IOException("canceled due to " + t);
          canceledException.addSuppressed(t);
          // 请求出了异常,在这里作失败回调
          responseCallback.onFailure(RealCall.this, canceledException);
        }
        throw t;
      } finally {
        // 最终结束.表示该call任务不再运作了.
        client.dispatcher().finished(this);
      }
    }
  }


  // 核心重点来了, 责任链设计模式.
  Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    // 这里创建拦截器集合
    List<Interceptor> interceptors = new ArrayList<>();
    // 对okHttpClient现有的拦截器进行获取,添加到集合中去
    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());

    boolean calledNoMoreExchanges = false;
    try {
      // 拦截链对原始request对象进行读取,由此获得response对象
      Response response = chain.proceed(originalRequest);
      if (transmitter.isCanceled()) {
        closeQuietly(response);
        throw new IOException("Canceled");
      }
      // 返回response响应体
      return response;
    } catch (IOException e) {
      calledNoMoreExchanges = true;
      throw transmitter.noMoreExchanges(e);
    } finally {
      if (!calledNoMoreExchanges) {
        transmitter.noMoreExchanges(null);
      }
    }
  }
}







// 这就是前面说到的NamedRunnable
public abstract class NamedRunnable implements Runnable {
  protected final String name;

  public NamedRunnable(String format, Object... args) {
    this.name = Util.format(format, args);
  }
  
  // 一旦runnable被执行 那么就会走到execute方法. 所以前面的AsyncCall里面的execute就被调起来了
  @Override public final void run() {
    String oldName = Thread.currentThread().getName();
    Thread.currentThread().setName(name);
    try {
      execute();
    } finally {
      Thread.currentThread().setName(oldName);
    }
  }

  protected abstract void execute();
}

在这里 我们得知response其实是根据RealInterceptorChain生成的chain链在其proceed方法之后处理得来的.

 

 

看到这里, 我们已经捋顺了OkHttp的整个请求方法的源码思路了, 当然这里留下一块还没分析, 就是"拦截器", 将交由下一篇文章再进行分析.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值