Okhttp框架

116 阅读2分钟

使用

val client = OkHttpClient.Builder().build()

val request = Request.Builder()
	.url("https://www.baidu.com")
	.build()

client.newCall(request).enqueue(object : okhttp3.Callback {
  override fun onResponse(call: okhttp3.Call, response: okhttp3.Response) {

  }

  override fun onFailure(call: okhttp3.Call, e: IOException) {

  }
})

分析

1. RealCall

通过创建的client的newRealCall创建一个RealCall对象,同时这个创建出的realCall对象也会吃有一个client的引用和外部创建的request对象,这个对象包括我们自己配置的属性像url之类

  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;
  }

后面就会调用创建的这个call对象的enqueue方法,把callback对象传进来,用来在请求完成(或者失败)的时候通过这个对象把消息传出去

@Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    transmitter.callStart();
  	//这里会把callback包进一个AsynCall对象中,这个类最后就就是继承的Runnable
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

这里可以看到把一个Runable传给了一个dispatcher的enqueue方法中,由此可以知道这里面一定会有thread去调用我们传进来的runable对象,执行它的run方法,实际上是走的execute方法

2. 切换线程

  /** Executes calls. Created lazily. */
  private @Nullable ExecutorService executorService;

  /** Ready async calls in the order they'll be run. */
  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();

  /** 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<>();

这几个就是dispatch类的变量,我们传来的的call对象最后被放进了readyAsyncCalls这个双端队列中等待线程调用

 void enqueue(AsyncCall call) {
    synchronized (this) {
      readyAsyncCalls.add(call);

      // Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to
      // the same host.
      if (!call.get().forWebSocket) {
        AsyncCall existingCall = findExistingCallWithHost(call.host());
        if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
      }
    }
    promoteAndExecute();
  }

紧接着就来到了最关键的方法

  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.
        //判断是否超过了一个端口最大请求数量,一般是2个
        if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity.

        i.remove();
        asyncCall.callsPerHost().incrementAndGet();
        executableCalls.add(asyncCall);
        //把对象放进另一个队列中
        runningAsyncCalls.add(asyncCall);
      }
      isRunning = runningCallsCount() > 0;
    }
		//遍历处理好的running队列,去执行它的executeOn方法
    for (int i = 0, size = executableCalls.size(); i < size; i++) {
      AsyncCall asyncCall = executableCalls.get(i);
      asyncCall.executeOn(executorService());
    }

    return isRunning;
  }

切换线程

 void executeOn(ExecutorService executorService) {
   assert (!Thread.holdsLock(client.dispatcher()));
   boolean success = false;
   try {
     //使用executorService来切换线程,这就实现了网络请求从主线程来到了子线程,完成后会通过callback把请求结果回调回去,这时候我们需要自己手动再切换回主线程去做一些页面刷新操作
     executorService.execute(this);
     success = true;
   } catch (RejectedExecutionException e) {
     InterruptedIOException ioException = new InterruptedIOException("executor rejected");
     ioException.initCause(e);
     transmitter.noMoreExchanges(ioException);
     responseCallback.onFailure(RealCall.this, ioException);
   } finally {
     if (!success) {
       client.dispatcher().finished(this); // This call is no longer running!
     }
   }
 }
  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;
  }

okhttp自定义了一个线程池,这个线程池看起来和cachethreadPool差不多,都是可以存放无限的线程,但是我们网络请求其实不能无限创建,这时候的限制逻辑其实是放在前面的遍历方法中去做过滤,这里使用无限的写法也不会有问题

3. 实际进行网络请求

 @Override protected void execute() {
   boolean signalledCallback = false;
   transmitter.timeoutEnter();
   try {
     //真正进行网络请求,连接建立,往sock写和读数据等都是这一行
     Response response = getResponseWithInterceptorChain();
     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);
     }
   } catch (Throwable t) {
     cancel();
     if (!signalledCallback) {
       IOException canceledException = new IOException("canceled due to " + t);
       canceledException.addSuppressed(t);
       responseCallback.onFailure(RealCall.this, canceledException);
     }
     throw t;
   } finally {
     //注意这里进行了最后的工作,像前面我们遍历时候没有放进running队列中的请求,这时候再次去看一下是否可以再次请求
     client.dispatcher().finished(this);
   }
 }
 private <T> void finished(Deque<T> calls, T call) {
    Runnable idleCallback;
    synchronized (this) {
      if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
      idleCallback = this.idleCallback;
    }

    boolean isRunning = promoteAndExecute();

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