Android okhttp源码流程原理解析(1)分发器

267 阅读2分钟

本篇内容

okhttp的源码流程主要逻辑就分为两块1.分发器 2.拦截器。上篇分析一下整体流程和分发器。

okhttp的优点

  1. 支持http1.1、2,quic以及websocket
  2. 连接池复用底层tcp(socket),减少请求时延
  3. 支持GZIP压缩,减少流量,传输快
  4. 缓存数据,减少重复的网络请求
  5. 支持失败自动重试与重定向

okhttp整体流程图

okhttp整体流程.drawio.png

分发器Dispatcher类配置

public final class Dispatcher {
  //同时存在最大请求数
  private int maxRequests = 64;
  //同host最多支持请求数
  private int maxRequestsPerHost = 5;
  //闲置任务
  private @Nullable Runnable idleCallback;
  //线程池
  private @Nullable ExecutorService executorService;
  //异步请求等待执行队列
  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
  //异步请求运行队列
  private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
  //同步请求执行队列
  private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
  }

1.分发器

同步请求做了什么?

  //只是将任务添加到了同步请求运行队列中
  synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);
  }

异步请求做了什么?

异步请求首先做判断,条件1小于最大请求数64(考虑客户端手机的压力),条件2同一host小于5个请求(考虑服务端的压力)

  synchronized void enqueue(AsyncCall call) {
    //两个判断
    //最大线程数<64 同一个host小于5 才会添加到执行队列
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      //添加到执行队列
      runningAsyncCalls.add(call);
      //线程池执行任务
      executorService().execute(call);
    } else {
      //否则添加到等待队列
      readyAsyncCalls.add(call);
    }
  }
  
  //线程池配置
    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;
  }

2.同步请求流程

        //构造request请求
        Request request = new Request.Builder()
                .url("http://baidu.com")
                .build();
        //构造okhttpclient对象
        OkHttpClient okHttpClient = new OkHttpClient()
                .newBuilder()
                .build();
        //构造runnable call对象
        Call call = okHttpClient.newCall(request);
        try {
            //调用同步方法
            call.execute();
        } catch (IOException e) {
            e.printStackTrace();
        }
        
//call是接口,真正的实现类是RealCall 
@Override public Response execute() throws IOException {
  try {
    //使用分发器方法 上面的分发器中已经说过只是将任务加入了同步执行队列,只是记录一下。
    client.dispatcher().executed(this);
    //*****************************************
    //真正请求的方法是getResponseWithInterceptorChain
    Response result = getResponseWithInterceptorChain();
    if (result == null) throw new IOException("Canceled");
    return result;
  } catch (IOException e) {
    eventListener.callFailed(this, e);
    throw e;
  } finally {
    client.dispatcher().finished(this);
  }
}
//这一步知道从拦截器链中获取响应就好了,拦截器在下一篇详细讲解
Response getResponseWithInterceptorChain() throws IOException {
  // Build a full stack of interceptors.
  List<Interceptor> interceptors = new ArrayList<>();
  interceptors.addAll(client.interceptors());
  //省略
}  

流程大概如下,不纠结细节代码。

同步流程.drawio.png

3.异步请求流程

//构造request请求
Request request = new Request.Builder()
        .url("http://baidu.com")
        .build();
//构造okhttpclient对象
OkHttpClient okHttpClient = new OkHttpClient()
        .newBuilder()
        .build();
//构造runnable call对象
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 {

    }
});

//添加到分发器中Dispatcher
client.dispatcher().enqueue(new AsyncCall(responseCallback));

synchronized void enqueue(AsyncCall call) {
    //两个判断
    //最大线程数<64 同一个host小于5 才会添加到执行队列
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      //添加到执行队列
      runningAsyncCalls.add(call);
      //线程池执行任务
      executorService().execute(call);
    } else {
      //否则添加到等待队列
      readyAsyncCalls.add(call);
    }
  }

到这里分发器的工作基本上已经说完了。