Okhttp3原码解析(一)

首先看一下Okhttp3是怎么进行请求的

//创建OkHttpClient对象
OkHttpClient client = new OkHttpClient.Builder().readTimeout(5, TimeUnit.SECONDS)
        .writeTimeout(5, TimeUnit.SECONDS)
        .connectTimeout(5, TimeUnit.SECONDS).build();
Request request = new Request.Builder().url("www.baidu.com").get().build();//创建Request对象
Call call = client.newCall(request);//将Request封装成Call 再用Call进行同步或者异步请求

同步请求:

//同步 :开始请求后就会进入阻塞状态,直接接到响应
try {
    Response response = call.execute();//响应报文的信息,比如响应头,体...
} catch (IOException e) {
    e.printStackTrace();
}

异步请求:

//异步 :不会阻塞当前线程
call.enqueue(new Callback() {
    @Override
    public void onFailure(@NonNull Call call, @NonNull IOException e) {
    }
    @Override
    public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
    }
});

以上就是Okhttp的用法,接下来我们来分析一下请求里面做了什么操作

先看一下client.newCall(request)这个方法

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

其实是创建了RealCall类,再跟进new RealCall里面看下

RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
 
//将client和之前创建的request在这里面进行了赋值,并且创建了一个拦截器RetryAndFollowUpInterceptor(也叫重定向拦截器,后面会再进行分析)
  final EventListener.Factory eventListenerFactory = client.eventListenerFactory();
  this.client = client;
  this.originalRequest = originalRequest;
  this.forWebSocket = forWebSocket;
  this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
  // TODO(jwilson): this is unsafe publication and not threadsafe.
  this.eventListener = eventListenerFactory.create(this);
}

再进一步看看call.execute()里面是怎么操作的(其实就是在RealCall里面具体实现)看如下代码

@Override public Response execute() throws IOException {
  synchronized (this) {
    //这个代码就是让同一个请进只能进行一次操作
     if (executed) throw new IllegalStateException("Already Executed");
    executed = true;
  }
  captureCallStackTrace();
  try {
    client.dispatcher().executed(this);//用dispatcher(调度器)分配执行的任务
    Response result = getResponseWithInterceptorChain();//获取响应报文和一些拦截器操作,以后会重点介绍
    if (result == null) throw new IOException("Canceled");
    return result;
  } finally {
    client.dispatcher().finished(this);
  }
}

再看看Dispatch的executed方法

private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
通过dispahch将call请求添加到了同步请求队列里面,很简单
//dispatch的executed方法
synchronized void executed(RealCall call) {
  runningSyncCalls.add(call);
}

再看一下异步的方法

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

看看dispatcher的enqueque,跟同步就大不一样,看以下几个方法

private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();//正在执行的异步请求队列
private int maxRequests = 64;//最大的请求队列
private int maxRequestsPerHost = 5;//最大请求主机数
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();//异步缓存队列
synchronized void enqueue(AsyncCall call) {
    //如果正在执行的异步请求队列小于最大的请求队列  及 最大的请求主机数小于设置值时 则将任务添加到正在执行的异步队列中然后执行
  if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
    runningAsyncCalls.add(call);
    executorService().execute(call);//创建线程池并且执行该任务
  } else {//同理将其添加到缓存队列中
    readyAsyncCalls.add(call);
  }
}
public synchronized ExecutorService executorService() {//创建线程池
  if (executorService == null) {
    //0:当核心线程数为0时,一段时间后会将里面的所有线程给清掉;Integer.MAX_VALUE最大的线程数其实在okhttp3里面不会超过64; 60:大于核心线程数时,每个线程最长的存活时间60S
     executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS
        new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false
  }
  return executorService;
}

异步方法执行任务最终也会调用到getRequestWithInterseptorChain方法中,我们在调用异步请求时会将Callback封装成AsynCall,其实AsynCall继承NamedRunnable最终继承Runnable 当执行请求任务时就会调用到AsynCall的execute()方法,其实当线程池执行队列任务里就会执行asynCall的run方法 以下是代码AsynCall的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);//最终都会走到这,将任务结束掉
  }
}
void finished(AsyncCall call) {//异步结束任务的代码
  finished(runningAsyncCalls, call, true);
}
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!");//先将任务remove掉
    if (promoteCalls) promoteCalls();//异步promoteCalls传过来的是true,如果会走promoteCalls()方法,就是对任务进行重新排列
    runningCallsCount = runningCallsCount();
    idleCallback = this.idleCallback;
  }
  if (runningCallsCount == 0 && idleCallback != null) {
    idleCallback.run();
  }
}
//将异步正在执行的任务队列和缓存队列任务进行重新排列
private void promoteCalls() {
  if (runningAsyncCalls.size() >= maxRequests) return; // 大于64return
  if (readyAsyncCalls.isEmpty()) return; //缓存队列没有任务,return
  for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
    AsyncCall call = i.next();//取到第一个缓存队列里的任务
    if (runningCallsForHost(call) < maxRequestsPerHost) {//判断请求主机数是否大于5
      i.remove();//将任务从缓存队列中移除
      runningAsyncCalls.add(call);//再添加到异步执行队列中
      executorService().execute(call);//最后在线程池中执行该任务
    }
    if (runningAsyncCalls.size() >= maxRequests) return; // 正在执行的队列大小小>=64 结束循环
  }
}

所以异步缓存队列里的任务是在promoteCalls方法中执行的.

Okhttp3网络请求简单的分析到这也就结束了,有时间再对里面再具体的细节进行分析






猜你喜欢

转载自blog.csdn.net/qq_35651451/article/details/80843478
今日推荐