美文网首页
okhttp网络框架源码浅析(一)

okhttp网络框架源码浅析(一)

作者: 源来是你啊 | 来源:发表于2018-07-30 21:18 被阅读0次

okhttp使用

app下gradle文件中引入okhttp

    //引入okhttp
    api 'com.squareup.okhttp3:okhttp:3.5.0'
okhttp同步请求
        //1.创建okhttp对象
        OkHttpClient client = new OkHttpClient.Builder()
            .readTimeout(5, TimeUnit.SECONDS)
            .build();
        //2.创建请求对象
        Request request = new Request.Builder()
                .url("https://www.baidu.com")
                .get()
                .build();
        //3.将request封装成call请求对象
        Call call = client.newCall(request);

        try {
            //4.执行call请求 获取响应
            Response response = call.execute();
            //输出报文
            System.out.println(request.body().toString());

        } catch (IOException e) {
            e.printStackTrace();
        }

以上即为okhttp请求网络的四个步骤,那么在这四个步骤的背后,okhttp做了哪些工作呢?

1.okhttp构造函数

  //分发请求进入执行队列,核心类
  final Dispatcher dispatcher;
  //请求代理
  final Proxy proxy;
  //协议列表
  final List<Protocol> protocols;
  //连接列表
  final List<ConnectionSpec> connectionSpecs;
  //拦截器列表
  final List<Interceptor> interceptors;
  //网络拦截器列表
  final List<Interceptor> networkInterceptors;
  final ProxySelector proxySelector;
  //cookie的保存策略
  final CookieJar cookieJar;
  //缓存
  final Cache cache;
  final InternalCache internalCache;
  //通讯工厂
  final SocketFactory socketFactory;
  final SSLSocketFactory sslSocketFactory;
  //安全证书管理者
  final CertificateChainCleaner certificateChainCleaner;
  //主机域名验证
  final HostnameVerifier hostnameVerifier;
  final CertificatePinner certificatePinner;
  final Authenticator proxyAuthenticator;
  final Authenticator authenticator;
  //连接池
  final ConnectionPool connectionPool;
  //域名解析器
  final Dns dns;
  final boolean followSslRedirects;
  final boolean followRedirects;
  final boolean retryOnConnectionFailure;
  final int connectTimeout;
  final int readTimeout;
  final int writeTimeout;
  //发送请求时间间隔
  final int pingInterval;

  public OkHttpClient() {
    this(new Builder());
  }
  //builder构建模式,初始化okhttp一系列属性值
  OkHttpClient(Builder builder) {
    this.dispatcher = builder.dispatcher;
    this.proxy = builder.proxy;
    this.protocols = builder.protocols;
    this.connectionSpecs = builder.connectionSpecs;
    this.interceptors = Util.immutableList(builder.interceptors);
    this.networkInterceptors = Util.immutableList(builder.networkInterceptors);
    this.proxySelector = builder.proxySelector;
    this.cookieJar = builder.cookieJar;
    this.cache = builder.cache;
    this.internalCache = builder.internalCache;
    this.socketFactory = builder.socketFactory;

    boolean isTLS = false;
    for (ConnectionSpec spec : connectionSpecs) {
      isTLS = isTLS || spec.isTls();
    }

    if (builder.sslSocketFactory != null || !isTLS) {
      this.sslSocketFactory = builder.sslSocketFactory;
      this.certificateChainCleaner = builder.certificateChainCleaner;
    } else {
      X509TrustManager trustManager = systemDefaultTrustManager();
      this.sslSocketFactory = systemDefaultSslSocketFactory(trustManager);
      this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
    }

    this.hostnameVerifier = builder.hostnameVerifier;
    this.certificatePinner = builder.certificatePinner.withCertificateChainCleaner(
        certificateChainCleaner);
    this.proxyAuthenticator = builder.proxyAuthenticator;
    this.authenticator = builder.authenticator;
    this.connectionPool = builder.connectionPool;
    this.dns = builder.dns;
    this.followSslRedirects = builder.followSslRedirects;
    this.followRedirects = builder.followRedirects;
    this.retryOnConnectionFailure = builder.retryOnConnectionFailure;
    this.connectTimeout = builder.connectTimeout;
    this.readTimeout = builder.readTimeout;
    this.writeTimeout = builder.writeTimeout;
    this.pingInterval = builder.pingInterval;
  }

  public OkHttpClient build() {
      return new OkHttpClient(this);
    }
  //这是builder类中的构造方法,初始化okhttp
  public Builder() {
      dispatcher = new Dispatcher();
      protocols = DEFAULT_PROTOCOLS;
      connectionSpecs = DEFAULT_CONNECTION_SPECS;
      proxySelector = ProxySelector.getDefault();
      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;
      connectTimeout = 10_000;
      readTimeout = 10_000;
      writeTimeout = 10_000;
      pingInterval = 0;
    }

以上okhttp构造函数主要做一些初始化操作,配置一些okhttp属性,完成okhttp对象的创建。

2.创建Request请求对象

由第二步可知,Request的构建也是采用builder模式创建,看下源码

  final HttpUrl url;
  final String method;
  final Headers headers;
  final RequestBody body;
  final Object tag;

  private volatile CacheControl cacheControl; // Lazily initialized.

  Request(Builder builder) {
    this.url = builder.url;
    this.method = builder.method;
    this.headers = builder.headers.build();
    this.body = builder.body;
    this.tag = builder.tag != null ? builder.tag : this;
  }

  public Request build() {
      if (url == null) throw new IllegalStateException("url == null");
      return new Request(this);
    }

这里主要也是构建request,初始化一些属性,包括请求地址url,请求方式,请求头,tag值(作用是用于取消网络请求的,具体会在后面有介绍)等等

3.将request封装为call请求

okhttpclient类

@Override public Call newCall(Request request) {
    return new RealCall(this, request, false /* for web socket */);
  }

RealCall类

final class RealCall implements Call {
  final OkHttpClient client;
  //拦截器
  final RetryAndFollowUpInterceptor retryAndFollowUpInterceptor;

  /** The application's original request unadulterated by redirects or auth headers. */
  final Request originalRequest;
  //标志位 是否为webSocket协议
  final boolean forWebSocket;

  // Guarded by this.
  private boolean executed;

  RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    this.client = client;
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
  }
}

可以看到RealCall继承自Call类,并对其进一步封装。

4.执行call请求

第四步是整个okhttp的核心步骤,这一步的背后进行了大量的操作。
RealCall类

final class RealCall implements Call {
  final OkHttpClient client;
  final RetryAndFollowUpInterceptor retryAndFollowUpInterceptor;

  /** The application's original request unadulterated by redirects or auth headers. */
  final Request originalRequest;
  final boolean forWebSocket;

  // Guarded by this.
  private boolean executed;

  RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    this.client = client;
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
  }

  @Override public Request request() {
    return originalRequest;
  }
   //执行请求
  @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);
    }
  }

  private void captureCallStackTrace() {
    Object callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()");
    retryAndFollowUpInterceptor.setCallStackTrace(callStackTrace);
  }

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

在RealCall中的execute方法中,最重要的两行代码:

      client.dispatcher().executed(this);
      Response result = getResponseWithInterceptorChain();

client.dispatcher().executed(this):client.dispatcher()是okhttp的核心类,主要是将Call请求添加到执行队列中

/** Used by {@code Call#execute} to signal it is in-flight. */
  synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);
  }

getResponseWithInterceptorChain():此方法创建一系列的拦截器,将realCall请求封装为真正的网络请求,最后请求服务器返回数据。
这里很多人有疑问:在加入到队列中后,执行getResponseWithInterceptorChain()获取数据,然后执行return返回数据,runningSyncCalls队列中并没有释放掉已经完成的请求。其实不然,在return response之后,finally还是会执行,释放已完成的请求。
Java finally语句到底是在return之前还是之后执行?

Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    //将所有客户端自定义的拦截器加入拦截器列表
    interceptors.addAll(client.interceptors());
    //retryAndFollowUpInterceptor这个拦截器主要重试失败请求
    interceptors.add(retryAndFollowUpInterceptor);
    //加入请求头信息,cookie策略,压缩协议等
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    //判断缓存是否过期,若有缓存则返回缓存数据
    interceptors.add(new CacheInterceptor(client.internalCache()));
    //建立网络连接
    interceptors.add(new ConnectInterceptor(client));
    //如果不是websocket协议,就加入用户自定义的网络拦截器
    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);
  }

将整个拦截链执行完毕后,会返回Response数据,整个访问网络请求就执行完毕。

重点:在以上同步代码当中,没有切换任何线程,所以如果在android平台上运行同步请求,请记住一定要另起线程(子线程)进行同步请求。

okhttp异步请求

以为为okhttp的异步请求,前三步与同步请求一致

OkHttpClient client = new OkHttpClient.Builder()
                .readTimeout(5, TimeUnit.SECONDS)
                .build();
        Request request = new Request.Builder().url("https://www.baidu.com")
                .get().build();

        Call call = client.newCall(request);
        //请求入队列
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                System.out.println("Fail");
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {

                System.out.println(response.body().string());

            }
        });

那么call.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));
  }

首先判断这个call是否已经执行,然后调用dispatcher().enqueue()将其加入执行队列,注意这里的传入的参数是AsyncCall,它是将RealCall封装为Runnable对象(AsyncCall继承自NamedRunnable,而NamedRunable继承自Runable)。

public abstract class NamedRunnable implements Runnable {
  protected final String name;

  public NamedRunnable(String format, Object... args) {
    this.name = Util.format(format, args);
  }

  @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();
}

言归正传,看看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.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);
      }
    }

首先执行的又是我们熟悉的getResponseWithInterceptorChain(),然后判断retryAndFollowUpInterceptor重试拦截器是否取消,若取消则说明责任链只执行到retryAndFollowUpInterceptor,抛出异常,执行失败;否则执行成功返回数据,回调onResponse(此回调在子线程);最后在finally模块当中执行finish()。

private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
    int runningCallsCount;
    Runnable idleCallback;
    synchronized (this) {
      if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
      if (promoteCalls) promoteCalls();
      runningCallsCount = runningCallsCount();
      idleCallback = this.idleCallback;
    }

    if (runningCallsCount == 0 && idleCallback != null) {
      idleCallback.run();
    }
  }

在finish()函数中,移除刚刚执行完成的异步任务,并且通过promoteCalls()函数判断执行队列是否已满;若未满,则将遍历取出等待队列中的任务添加到执行队列中,直到执行队列达到最大数量。

okhttp执行流程图
okhttp网络框架源码浅析(二)

相关文章

网友评论

      本文标题:okhttp网络框架源码浅析(一)

      本文链接:https://www.haomeiwen.com/subject/lgrfvftx.html