Android学习之旅

OkHttp - 源码解析

2019-10-26  本文已影响0人  pj0579

特点:
支持HTTP2/SPDY黑科技(Http2 优化了头部压缩,多路复用多个http请求共用一个TCP连接)
socket自动选择最好路线,并支持自动重连
拥有自动维护的socket连接池,减少握手次数
拥有队列线程池,轻松写并发
拥有Interceptors轻松处理请求与响应(比如透明GZIP压缩,LOGGING)
实现基于Headers的缓存策略
内部有几个比较重要的类:

OkHttpClient:

老规矩还是从最简单的代码来分析一下


        OkHttpClient client = new OkHttpClient.Builder().build();
        Request request = new Request.Builder().
                url("https://www.baidu.com").
                build();
        Call call = client.newCall(request);
        try {
            //1.同步请求方式
            Response response = call.execute();
            //2.异步请求方式
            call.enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    // 获取失败
                }
                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    // 获取成功
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }

先看OkHttpClientBuild方法

 public Builder() {
      dispatcher = new Dispatcher();// 分发器  控制并发 保存了同步和异步的call(线程池执行)
      protocols = DEFAULT_PROTOCOLS; // http协议
      connectionSpecs = DEFAULT_CONNECTION_SPECS; // 连接配置
      eventListenerFactory = EventListener.factory(EventListener.NONE); // 监听器
      proxySelector = ProxySelector.getDefault(); // 代理选择
      cookieJar = CookieJar.NO_COOKIES;// 默认没有cookie
      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;
      coBnectTimeout = 10_000;
      readTimeout = 10_000;
      writeTimeout = 10_000;
      pingInterval = 0;
    }

Build 方法创建了默认的设置,当继续调用build方法时会采用默认设置创建OkHttpClient对象。这时如果需要改变默认的属性,可以这样设置

new OkHttpClient.Builder().connectTimeout(DEFAULT_CONNECT_TIMEOUT, TimeUnit.SECONDS).build();

Request

接着看Request

public final class Request {
  final HttpUrl url;
  final String method;
  final Headers headers;
  final @Nullable RequestBody body;
  final Object tag;
  private volatile CacheControl cacheControl; // Lazily initialized.
  }

看到这个类包含类请求的url ,method,headers,body,缓存控制等等。
接着往下分析

Call

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

RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    final EventListener.Factory eventListenerFactory = client.eventListenerFactory();
    this.client = client;
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
    this.eventListener = eventListenerFactory.create(this);
  }

RealCall是实现Call的子类,真正进行操作的类

Response

首先看下同步请求的

@Override public Response execute() throws IOException {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    try {
      // 这边直接放入Running队列中执行
      client.dispatcher().executed(this);
      Response result = getResponseWithInterceptorChain();
      if (result == null) throw new IOException("Canceled");
      return result;
    } finally {
      client.dispatcher().finished(this);
    }
  }

真正进行网络请求的是Response result = 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);
  }

这些Interceptor完成了一系列的链式使用,CallServerInterceptor负责向服务器请求数据是最后一个,这个类的intercept不会再次调用下一个Interceptorintercept方法。ConnectInterceptor负责建立连接,具体怎么实现可以看下代码,不过肯定逃不过Soket的使用,再看下CallServerInterceptorintercept方法。

 @Override public Response intercept(Chain chain) throws IOException {
  HttpCodec httpCodec = ((RealInterceptorChain) chain).httpStream();
  StreamAllocation streamAllocation = ((RealInterceptorChain) chain).streamAllocation();
  Request request = chain.request();

  long sentRequestMillis = System.currentTimeMillis();
  httpCodec.writeRequestHeaders(request);

  if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
    Sink requestBodyOut = httpCodec.createRequestBody(request, request.body().contentLength());
    BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
    request.body().writeTo(bufferedRequestBody);
    bufferedRequestBody.close();
  }

  httpCodec.finishRequest();

  Response response = httpCodec.readResponseHeaders()
      .request(request)
      .handshake(streamAllocation.connection().handshake())
      .sentRequestAtMillis(sentRequestMillis)
      .receivedResponseAtMillis(System.currentTimeMillis())
      .build();

  if (!forWebSocket || response.code() != 101) {
    response = response.newBuilder()
        .body(httpCodec.openResponseBody(response))
        .build();
  }

  if ("close".equalsIgnoreCase(response.request().header("Connection"))
      || "close".equalsIgnoreCase(response.header("Connection"))) {
    streamAllocation.noNewStreams();
  }
  ...
  return response;
}

最后由HttpCodec发起网络请求。
然后再看下异步网络请求,按照思路基本流程肯定相似,完成异步操作肯定需要新开线程完成操作。

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

看下AsyncCall 怎么包装的

// Dispatcher
 synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      // 提交线程池执行
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }
// AsyncCall 
final class AsyncCall extends NamedRunnable {
    private final Callback responseCallback;

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

    String host() {
      return originalRequest.url().host();
    }

    Request request() {
      return originalRequest;
    }

    RealCall get() {
      return RealCall.this;
    }

    @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);
      }
    }
  }
// AsyncCall 继承的NamedRunnable
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();
}

Response response = getResponseWithInterceptorChain();这个就和之前的同步请求一摸一样。
梳理一下整个流程

整个流程
上一篇下一篇

猜你喜欢

热点阅读