OkHttp源码解读

本文使用的okhttp版本是:2.7.5

compile group: 'com.squareup.okhttp', name: 'okhttp', version: '2.7.5'

简单使用

使用okhttp发送一个网络请求是十分的方便的

OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder().url("").build();//建造者设计模式
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {

    @Override
    public void onFailure(Request request, IOException e) {
		//请求失败的回调
    }

    @Override
    public void onResponse(Response response) throws IOException {
		//请求成功的回调
    }
});

源码解读

先看一下call.enqueue()做了啥

public void enqueue(Callback responseCallback) {
    enqueue(responseCallback, false);
  }

  void enqueue(Callback responseCallback, boolean forWebSocket) {
    synchronized (this) {//加同步锁
    	//如果已经执行过了,就抛异常
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    //这里的client就是okHttpClient,这里调用了okhttclient中的dispatcher的enqueue方法,new AsyncCall(responseCallback, forWebSocket)是对responseCallback的二次封装
    client.getDispatcher().enqueue(new AsyncCall(responseCallback, forWebSocket));
  }

继续看下enqueue(),runningCalls、readyCalls都是ArrayDeque(循环队列),runningCalls存储是正在执行中的AsyncCall,readyCalls存储的是将要执行的AsyncCall。

  synchronized void enqueue(AsyncCall call) {
  	//runningCalls、readyCalls都是ArrayDeque(循环队列),runningCalls存储是正在执行中的AsyncCall,readyCalls存储的是将要执行的AsyncCall。
    if (runningCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
    //加入到运行队列中
      runningCalls.add(call);
      //直接利用线程池去执行这个AsyncCall
      getExecutorService().execute(call);
    } else {
    //加入到等待队列中
      readyCalls.add(call);
    }
  }

看下ExecutorService (),注意这里的创建了一个线程池,线程池的核心线程数量为0,最大线程数量为Integer.MAX_VALUE,空闲超时时间为60秒,SynchronousQueue是一个无容量的等待队列。这个线程池的作用是:只要有任务来,就马上利用空闲的线程或者创建新线程去执行任务,线程的空闲时间超过60秒就会被撤销收回。(其实是一个可缓存线程池,将每一个空闲的线程都缓存60秒)

  public synchronized ExecutorService getExecutorService() {
    if (executorService == null) {
    	//创建了一个线程池,线程池的核心线程数量为0,最大线程数量为Integer.MAX_VALUE,空闲超时时间为60秒,SynchronousQueue是一个无容量的等待队列。这个线程池的作用是:只要有任务来,就马上利用空闲的线程或者创建新线程去执行任务,线程的空闲时间超过60秒就会被撤销收回。(其实是一个可缓存线程池)
      executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
          new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;
  }

getExecutorService().execute(call),这句代码线程池会执行call中的run方法,所以看一下AsyncCall的父类NamedRunnable中的run函数

  @Override public final void run() {
    String oldName = Thread.currentThread().getName();
    Thread.currentThread().setName(name);
    try {
    //就是说,线程池最终会执行execute()
      execute();
    } finally {
      Thread.currentThread().setName(oldName);
    }
  }
  //受保护的抽象方法
  protected abstract void execute();

看一下AsyncCall中execute()的具体实现,其实就是getResponseWithInterceptorChain函数去执行责任链中的每一个拦截器中的处理代码

@Override protected void execute() {
      boolean signalledCallback = false;
      try {
      //核心代码,开始执行责任链中的每个拦截器的拦截代码
        Response response = getResponseWithInterceptorChain(forWebSocket);
        if (canceled) {
          signalledCallback = true;
         //执行失败则回调onFailure
          responseCallback.onFailure(originalRequest, new IOException("Canceled"));
        } else {
          signalledCallback = true;
          //执行成功则回调onResponse
          responseCallback.onResponse(response);
        }
      } catch (IOException e) {
        if (signalledCallback) {
          // Do not signal the callback twice!
          logger.log(Level.INFO, "Callback failure for " + toLoggableString(), e);
        } else {
          Request request = engine == null ? originalRequest : engine.getRequest();
          responseCallback.onFailure(request, e);
        }
      } finally {
      //执行下一个call
        client.getDispatcher().finished(this);
      }
    }

getResponseWithInterceptorChain函数

  private Response getResponseWithInterceptorChain(boolean forWebSocket) throws IOException {
    Interceptor.Chain chain = new ApplicationInterceptorChain(0, originalRequest, forWebSocket);
    return chain.proceed(originalRequest);
  }

ApplicationInterceptorChain 是啥?细细一看,这就是大名鼎鼎的责任链设计模式了,等责任链中的拦截器都处理完之后,发送http请求并将相应结果返回。

class ApplicationInterceptorChain implements Interceptor.Chain {
	//执行到的节点下标
    private final int index;
    private final Request request;
    private final boolean forWebSocket;

    ApplicationInterceptorChain(int index, Request request, boolean forWebSocket) {
      this.index = index;
      this.request = request;
      this.forWebSocket = forWebSocket;
    }

    @Override public Connection connection() {
      return null;
    }

    @Override public Request request() {
      return request;
    }
	//责任链中的核心代码,执行链条中每个节点(拦截器)的业务
    @Override public Response proceed(Request request) throws IOException {
      // If there's another interceptor in the chain, call that.
      //获取拦截器
      if (index < client.interceptors().size()) {
        Interceptor.Chain chain = new ApplicationInterceptorChain(index + 1, request, forWebSocket);
        //得到链条中当前下标对应的拦截器
        Interceptor interceptor = client.interceptors().get(index);
        //执行拦截器中的拦截事件
        Response interceptedResponse = interceptor.intercept(chain);
		
        if (interceptedResponse == null) {
          throw new NullPointerException("application interceptor " + interceptor
              + " returned null");
        }

        return interceptedResponse;
      }

      // No more interceptors. Do HTTP.
      //责任链中的拦截器都处理完之后,发送http请求并将相应结果返回
      return getResponse(request, forWebSocket);
    }
  }

finished(),因为这个时候是已经执行完了call,所以这个函数作用是可以把call从运行队列runningCalls中移除,然后调用promoteCalls()去执行下一批call

  synchronized void finished(AsyncCall call) {
  //因为这个时候是已经执行完了call,所以可以把call从运行队列runningCalls中移除了
    if (!runningCalls.remove(call)) throw new AssertionError("AsyncCall wasn't running!");
    promoteCalls();
  }

调用promoteCalls,又开始用线程池去执行等待队列readyCalls中的网络请求任务call。其实就是遍历等待readyCalls中的每一个任务,用线程池去执行每一个call,并且将call加入到运行队列中,同时将该call从等待readCalls中删除。

private void promoteCalls() {
    if (runningCalls.size() >= maxRequests) return; // Already running max capacity.
    if (readyCalls.isEmpty()) return; // No ready calls to promote.
	//遍历等待readyCalls中的每一个任务,用线程池去执行每一个call,并且将call加入到运行队列中,同时将该call从等待readCalls中删除。
    for (Iterator<AsyncCall> i = readyCalls.iterator(); i.hasNext(); ) {
      AsyncCall call = i.next();

      if (runningCallsForHost(call) < maxRequestsPerHost) {
        i.remove();
        runningCalls.add(call);
        getExecutorService().execute(call);
      }

      if (runningCalls.size() >= maxRequests) return; // Reached max capacity.
    }
  }

源码解读结束

总结

okhttp其实就是把一个一个的网络请求封装成了一个一个的AsyncCall对象,AsyncCall中包含了请求url、请求内容还有用户自定好的请求失败或者成功之后的回调。okhttp同时维护了两个队列,一个是等待队列readyCalls、一个是runningCalls。在加入一个新的AsyncCall的时候,判断runningCalls中的任务数是否小于maxRequests(默认是64)并且runningCalls是否小于maxRequestsPerHost(默认是5),如果成立的话,就把AsyncCall加入到runningCalls,并且用一个可缓存线程池去执行这个任务;如果不成立的话,会把AsyncCall加入到等待队列readyCalls中。AsyncCall被执行的过程是:可缓存线程池会去执行AsyncCall中的execute函数,execute函数中就会启动一个责任链,责任链就会去执行okhttpclient中的每一个拦截器的处理代码,最后发送http请求并将结果返回,然后回调AsyncCall中的onFailure或者onResponse方法。回调完之后把运行队列runningCalls的已经执行结束的call给删除掉,然后继续遍历等待队列readyCalls,用可缓存线程池去执行其中的每一个call。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值