天天看点

Okhttp3源码

Okhttp3源码

hi,大家好,我是爱吃香蕉的猴子,Okhttp3的源码之前没有怎深入了解,最近看了很多Okhttp3源码的文章,看的云里雾里,在这我也不贴连接了,整理一篇自己理解的吧。

源码Githup地址 具体的使用过程上面也有介绍,现在步入正题。

从使用步骤切入,再进入源码,最后总结

OkHttpClient client = new OkHttpClient.Builder().build();
        Request request = new Request.Builder().
                url("https://github.com/square/okhttp").
                build();
        Call call = client.newCall(request);
        try {
            Response response = call.execute();
            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();
        }
           

上面的代码是规规矩矩的使用范例,现在我们逐一解析

  • ①OkHttpClient client = new OkHttpClient.Builder().build();
  • 第一步声明client对象,如何声明呢? 为什么通过Builder().builder()?
  • 那肯定要看OkHttpClient的代码; path: OkHttp\okhttp\okhttp\src\main\java\okhttp3\OkHttpClient.java
public Builder() {
      dispatcher = new Dispatcher();//重点 分析Dispatcher
      protocols = DEFAULT_PROTOCOLS;//默认支持的协议
      connectionSpecs = DEFAULT_CONNECTION_SPECS;//默认的连接规范
      eventListenerFactory = EventListener.factory(EventListener.NONE);
      proxySelector = ProxySelector.getDefault();//默认的代理选择器,直连
       ........
           
  • 在这个Builder构造器中,初始化了dispatcher, 在看一下build方法
public OkHttpClient build() {
      return new OkHttpClient(this);
    }
           

这样就声明了client对象,并初始化了dispatcher等等.

  • ②Request request = new Request.Builder().url().build();
  • 这一步就是初始化request; 方法和OkhttpClient很一样, 注释的大概意思:一个HTTP请求。我理解为对请求链接的处理吧
  • 然后主要就是要将request(数据请求连接)放入newCall中。
public Builder() {
      this.method = "GET"; //get的请求方式
      this.headers = new Headers.Builder();
    }
           
  • ③Call call = client.newCall(request);
  • 上面两步的执行,就是为第三步做准备的,现在 在okhttpclient中newCall方法声明了call对象.
/**
   * Prepares the {@code request} to be executed at some point in the future.
   */
  @Override public Call newCall(Request request) {
    return RealCall.newRealCall(this, request, false /* for web socket */);
  }
           
  • Call是一个interface, RealCall是真正的实现类,可以着重看RealCall;
  • path: OkHttp\okhttp\okhttp\src\main\java\okhttp3\RealCall.java
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, 这样就要开始异步请求的工作;

  • ④ call.enqueue(new Callback() {
@Override public void enqueue(Callback responseCallback) {
     。。。。
    //client.dispatcher()返回一个Dispatcher对象,异步请求调度器,里面会对任务进行分辨,是立刻执行还是放入等待队列
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }
           
  • 最后的代码中参数new AsyncCall(responseCallback); 我们来猜一下 这个类是干嘛的,我的直觉是和Runnable有关,因为毕竟异步请求嘛
  • final class AsyncCall extends NamedRunnable { //果然继承NameRunnable
  • 这样RealCall的代码暂时看到这里,现在看Dispatcher的enqueue方法;

path: OkHttp\okhttp\okhttp\src\main\java\okhttp3\Dispatcher.java

  • 先看一些变量
private int maxRequests = 64;//最大并发数为64,同时请求
  private int maxRequestsPerHost = 5;//每个主机的最大请求数为5
  private @Nullable Runnable idleCallback;//闲置接口
  /** 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<>();
           
void enqueue(AsyncCall call) {
    synchronized (this) {
    readyAsyncCalls.add(call);//缓存好的异步调用,都是放在队列里保存
      。。。
    //TODO 
    promoteAndExecute();//这一步就是增加线程池
  }
           

进入promoteAndExecute看一下

private boolean promoteAndExecute() {
        。。。。。
        //如果当前运行的异步请求队列长度小于最大请求数,也就是64,并且主机的请求数小于每个主机的请求数也就是5,
        //则把当前请求添加到 运行队列,接着交给线程池ExecutorService处理,否则则放置到readAsyncCall进行缓存,等待执行
        if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
        if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity.
    。。。。。
    for (int i = 0, size = executableCalls.size(); i < size; i++) {
      AsyncCall asyncCall = executableCalls.get(i);
      //进入线程池
      asyncCall.executeOn(executorService());
    }
    return isRunning;
  }
           
  • 网络请求数据,增加线程池 提高效率,进入线程池看一下–> executorService;
//同步最大的区别
  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;
  }
           
  • 小结:添加到线程池后就交给ThreadPoolExecutor去调用,最终则是调用到我们的请求AsyncCall的execute方法。回看上面的代码,异步请求中,我们传递了个Callback接口进来,而在RealCall的enqueue方法中,Callback回调接口被封装到AsyncCall中,而AsyncCall继承与NamedRunnable,而NamaedRunnable则实现了Runnable方法。
  • 现在,返回到RealCall中查看executeOn方法;

    path: OkHttp\okhttp\okhttp\src\main\java\okhttp3\RealCall.java # 内部类:AsyncCall

/**
     * Attempt to enqueue this async call on {@code executorService}. This will attempt to clean up
     * if the executor has been shut down by reporting the call as failed.
     */
    void executeOn(ExecutorService executorService) {
      assert (!Thread.holdsLock(client.dispatcher()));
      boolean success = false;
      try {
        executorService.execute(this);
           

进入executorService.execute(this);查看

@Override protected void execute() {
      boolean signalledCallback = false;
      transmitter.timeoutEnter();
      try {
        //重点: 看OkHttp如何连接返回
        Response response = getResponseWithInterceptorChain();
        signalledCallback = true;
        responseCallback.onResponse(RealCall.this, response);
           

现在要对返回值处理: getResponseWithInterceptorChain

Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());
    interceptors.add(new RetryAndFollowUpInterceptor(client));
    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, transmitter, null, 0,
        originalRequest, this, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());
           
  • 这样就分析到了,Okhttp的关键部分拦截器

    用户自定义连接器

RetryAndFollowUpInterceptor:在连接失败后进行重新连接,必要时进行重定向,如果调用被取消,可能会抛出IOException

BridgeInterceptor:构建访问网络的桥梁,首先,将用户请求转换成网络请求,然后访问网络,最后将网络响应转换成用户响应。

CacheInterceptor:缓存拦截器,从缓存中获取服务器请求,或者把服务器响应写入缓存中。

ConnectInterceptor:打开一个连接,去连接目标服务器。

CallServerInterceptor:拦截器链中的最后一个链点,通过网络请求服务器。