同步请求

OkHttpClient httpClient = new OkHttpClient();

String url = "https://www.baidu.com/";
Request getRequest = new Request.Builder()
        .url(url)
        .get()
        .build();

Call call = httpClient.newCall(getRequest);

new Thread(new Runnable() {
    @Override
    public void run() {
        try {
            //同步请求,要放到子线程执行
            Response response = call.execute();
            Log.i(TAG, "okHttpGet run: response:"+ response.body().string());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}).start();

总结:

  1. 创建OkHttpClient和Request对象

  2. 将Request封装成Call对象

  3. 调用Call的execute()发送同步请求

同步执行流程

第一步,创建一个OkHttpClient对象

OkHttpClient mClient = new OkHttpClient.Builder().build();
public Builder() {
      dispatcher = new Dispatcher();
      protocols = DEFAULT_PROTOCOLS;
      connectionSpecs = DEFAULT_CONNECTION_SPECS;
      eventListenerFactory = EventListener.factory(EventListener.NONE);
      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;
    }

重点关注Dispatcher、ConnectionPool的初始化。Dispatcher和异步请求有关,我们先不讲,我们重要讲一下ConnectionPool。

ConnectionPool有两个作用:

作用一,当你请求的url是相同的时候,就可以复用这个Connection;

作用二,ConnectionPool可以设置哪些Connection保持打开,哪些Connection可以保持复用;

第二步,创建携带请求信息的Request对象

Request request = new Request.Builder().url("http://www.baidu.com").get().build();

Builder(Request request) {
      this.url = request.url;
      this.method = request.method;
      this.body = request.body;
      this.tag = request.tag;
      this.headers = request.headers.newBuilder();
}

第三步,创建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;
  (1)重定向拦截器
  this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);

  // TODO(jwilson): this is unsafe publication and not threadsafe.
  this.eventListener = eventListenerFactory.create(this);
}

第四步,call.execute()

@Override public Response execute() throws IOException {
  (1)通过标注位一个请求只能执行一次
  synchronized (this) {
    if (executed) throw new IllegalStateException("Already Executed");
    executed = true;
  }
  (2)捕捉堆栈信息
  captureCallStackTrace();
  try {
    (3)将请求加入同步队列
    client.dispatcher().executed(this);
    Response result = getResponseWithInterceptorChain();
    if (result == null) throw new IOException("Canceled");
    return result;
  } finally {
    (4)移除请求
    client.dispatcher().finished(this);
  }

image.png

private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
  int runningCallsCount;
  Runnable idleCallback;
  synchronized (this) {
    (1)移除请求
    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();
  }
}

异步请求

 String url = "https://www.jianshu.com";
 OkHttpClient okHttpClient = new OkHttpClient();
 final Request request = new Request.Builder()
         .url(url)
         .get()//默认就是GET请求,可以不写
         .build();
 Call call = okHttpClient.newCall(request);
 call.enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {

    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        Log.d(TAG, "onResponse() returned: " + response);
    }
});

总结:

  1. 创建OkHttpClient和Request对象

  2. 将Request封装成Call对象

  3. 调用Call的enqueue()发送异步请求

异步请求执行流程

前三步和同步一样,不在分析。

第四步,call.enqueue()

@Override public void enqueue(Callback responseCallback) {
 (1)通过标注位一个请求只能执行一次
  synchronized (this) {
    if (executed) throw new IllegalStateException("Already Executed");
    executed = true;
  }
  captureCallStackTrace();
  client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
synchronized void enqueue(AsyncCall call) {
  if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
    runningAsyncCalls.add(call);
    executorService().execute(call);
  } else {
    readyAsyncCalls.add(call);
  }
}

正在异步请求数小于64并且当前url的host请求数小于5就放到正在运行的异步队列,否则放到等待的异步队列。

通过线程池运行AsyncCall。

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;
}
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 {
      (1)重点关注
      client.dispatcher().finished(this);
    }
  }
}
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
  int runningCallsCount;
  Runnable idleCallback;
  synchronized (this) {
    (1)移除当前请求
    if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
    (2)执行等待队列中的请求
    if (promoteCalls) promoteCalls();
    runningCallsCount = runningCallsCount();
    idleCallback = this.idleCallback;
  }

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

private void promoteCalls() {
  if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
  if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.

  for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
    AsyncCall call = i.next();

    if (runningCallsForHost(call) < maxRequestsPerHost) {
      i.remove();
      runningAsyncCalls.add(call);
      executorService().execute(call);
    }

    if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
  }
}

总结:

  1. 通过没有核心线程的线程池执行请求

  2. 在finally中正在运行的队列移除请求,并执行等待队列中的可以执行的请求。

参考:

 posted on 2022-01-22 20:18  石中玉97  阅读(110)  评论(0)    收藏  举报