OKhttp学习笔记--使用和源码分析

使用
同步

    String url = "https://wanandroid.com/wxarticle/chapters/json";
    OkHttpClient okHttpClient = new OkHttpClient();
    Request request= new Request.Builder().url(url).build();
    Response response = okHttpClient.newCall(request).execute();

异步

 String url  ="https://wanandroid.com/wxarticle/chapters/json";
    OkHttpClient okHttpClient = new OkHttpClient();
    Request request = new Request.Builder().url(url).build();
    okHttpClient.newCall(request).enqueue(new Callback() {
      @Override
      public void onFailure(okhttp3.Call call, IOException e) {
        
      }

      @Override
      public void onResponse(okhttp3.Call call, Response response) throws IOException {

      }
    });

还可以添加自定义拦截器、设置超时时间、请求过程事件监听、dns、缓存等等。。。
添加拦截器 和 事件监听的例子 更详细的功能使用看官方网站

OkHttpClient client = new OkHttpClient.Builder().eventListener(new EventListener() {
      @Override
      public void callStart(okhttp3.Call call) {
        super.callStart(call);
        System.out.println("callStart");
      }

      @Override
      public void dnsStart(okhttp3.Call call, String domainName) {
        super.dnsStart(call, domainName);
        System.out.println("dnsStart");
      }

      @Override
      public void dnsEnd(okhttp3.Call call, String domainName, List<InetAddress> inetAddressList) {
        super.dnsEnd(call, domainName, inetAddressList);
        System.out.println("dnsEnd");
      }
    }).addInterceptor(new Interceptor() {
      @Override
      public Response intercept(Chain chain) throws IOException {

        System.out.println("我先做点事情");


        return chain.proceed(chain.request());
      }
    }).build();
    Request request = new Request.Builder()
            .url(url)
            .build();
    Response response = client.newCall(request).execute();

    client.newCall(request).enqueue(new Callback() {
      @Override
      public void onFailure(okhttp3.Call call, IOException e) {

      }

      @Override
      public void onResponse(okhttp3.Call call, Response response) throws IOException {
        System.out.println(response.body().string());
      }
    });

源码分析 (主流程)
OkHttpClient 和 Request 通过建造者模式构建,主要是基础属性 拦截器、url、dns等等

同步请求源码流程
发起真正执行请求

Response response = client.newCall(request).execute();

最终是通过RealCall 去执行execute()

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

ReclCall里则是通过dispatcher 调度器去执行,同步请求时将call存入
runningSyncCalls 然后发起请求 通过责任链模式 返回结果后从队列中移除call,最终返回结果

@Override public Response execute() throws IOException {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    transmitter.timeoutEnter();
    transmitter.callStart();
    try {
      //加到同步队列中
      client.dispatcher().executed(this);
      //获取结果返回
      return getResponseWithInterceptorChain();
    } finally {
      //从同步队列中移除
      client.dispatcher().finished(this);
    }
  }

// client.dispatcher().executed(this)
 synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);
  }

异步请求源码流程

  client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(okhttp3.Call call, IOException e) {

            }

            @Override
            public void onResponse(okhttp3.Call call, Response response) throws IOException {
                System.out.println(response.body().string());
            }
        });

异步请求有两个队列 readyAsyncCalls和runningAsyncCalls
1、先是加入到readyAsyncCalls 队列 预备队列
2、从readyAsyncCalls和runningAsyncCalls 中找出和此次host相同的请求,如果存在记录个数
3、继续执行

 void enqueue(AsyncCall call) {
    synchronized (this) {
     //加入readyAsyncCalls队列
      readyAsyncCalls.add(call);

      // Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to
      // the same host.
      //RealCall的forWebSocket=false 
      if (!call.get().forWebSocket) {
        //从readyAsyncCalls和runningAsyncCalls 找出host相同的请求
        AsyncCall existingCall = findExistingCallWithHost(call.host());
        //如果找到相同的 则将host计数赋值
        if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
      }
    }
    //推动执行
    promoteAndExecute();
  }

//找出相同的host
@Nullable private AsyncCall findExistingCallWithHost(String host) {
    for (AsyncCall existingCall : runningAsyncCalls) {
      if (existingCall.host().equals(host)) return existingCall;
    }
    for (AsyncCall existingCall : readyAsyncCalls) {
      if (existingCall.host().equals(host)) return existingCall;
    }
    return null;
  }

接下来执行promoteAndExecute(),这里涉及一个逻辑 ,如何将readyAsyncCalls里的call转移到runningAsyncCalls中
规则是:如果runningAsyncCalls大于等于64 默认 或者正在执行的host 相同的已经超过5个默认 则不转移 每次取出要执行的call都是这样去判断的

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();
        //如果runningAsyncCalls大于等于maxRequests 默认64 则直接中断
        if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
        //或者 如果相同host大于等于maxRequestsPerHost 默认5 也不添加
        if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity.
        //从readyAsyncCalls中移除
        i.remove();
        //将host的次数++
        asyncCall.callsPerHost().incrementAndGet();
        //加入到可执行的executableCalls队列中 临时队列
        executableCalls.add(asyncCall);
        //加到runningAsyncCalls中
        runningAsyncCalls.add(asyncCall);
      }
      //是否正常执行  runningAsyncCalls.size() + runningSyncCalls.size()  同步队列或异步队列有数据则证明有在运行  因为运行结束会移除
      isRunning = runningCallsCount() > 0;
    }
    //将满足条件的可执行的call 执行 
    for (int i = 0, size = executableCalls.size(); i < size; i++) {
      AsyncCall asyncCall = executableCalls.get(i);
      //调用executeOn 其实是一个Runnable
      asyncCall.executeOn(executorService());
    }

    return isRunning;
  }

//AsyncCall 继承NamedRunnable 包装了一下

public abstract class NamedRunnable implements Runnable {
  protected final String name;

  public NamedRunnable(String format, Object... args) {
    this.name = Util.format(format, args);
  }

  @Override public final void run() {
    String oldName = Thread.currentThread().getName();
    Thread.currentThread().setName(name);
    try {
      execute();
    } finally {
      Thread.currentThread().setName(oldName);
    }
  }

  protected abstract void execute();
}

在AsyncCall中执行executeOn方法

void executeOn(ExecutorService executorService) {
      assert (!Thread.holdsLock(client.dispatcher()));
      boolean success = false;
      try {
        //线程池 执行runnable 即 execute()
        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!
        }
      }
    }

@Override protected void execute() {
      boolean signalledCallback = false;
      transmitter.timeoutEnter();
      try {
      //和同步请求一样  通过拦截器 获取结果 
        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 {
        //从runningAsyncCalls移除请求call 并且在相同的host上减1
        client.dispatcher().finished(this);
      }
    }
  }

除了五大拦截器 主线流程大致如此
五大拦截器大致逻辑(图片来自享学)
图片来自享学
备注下连接池 (图片来自享学)
在这里插入图片描述

核心线程数:0,不会缓存线程,所有线程60秒内没工作就会被回收
最大线程数为:Integer.MAX_VALUE
等待队列:SynchronousQueue,两者结合达最大吞吐量,没有空闲线程无需等待,直接创建新的执行
//连接池的线程池

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

清理任务的线程池

  private static final Executor executor = new ThreadPoolExecutor(0 /* corePoolSize */,
      Integer.MAX_VALUE /* maximumPoolSize */, 60L /* keepAliveTime */, TimeUnit.SECONDS,
      new SynchronousQueue<>(), Util.threadFactory("OkHttp ConnectionPool", true));
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值