okhttp3.7源码分析(一)

1.okhttp 特点:

1.支持HTTPS/HTTP2/WebSocket(在OkHttp3.7中已经剥离对Spdy的支持,转而大力支持HTTP2)
2.内部维护任务队列线程池,友好支持并发访问
3.内部维护连接池,支持多路复用,减少连接创建开销
4.socket创建支持最佳路由
5.提供拦截器链(InterceptorChain),实现request与response的分层处理(如透明GZIP压缩,logging等)

2.okhttp的同步和异步使用

同步

 OkHttpClient okHttpClient=new OkHttpClient();
    Request request=new Request.Builder().build();
    try {
        okHttpClient.newCall(request).execute();
    } catch (IOException e) {
        e.printStackTrace();
    }

1.new 一个okhttpclient对象,在其构造方法会初始化一系列数据(缓存,调度者,超时时间等)
在这里插入图片描述
在这里插入图片描述
2.通过Builder()方法初始化请求方法和请求头,然后通过build()方法做校验,new 出request对象
在这里插入图片描述
在这里插入图片描述
3.通过调用okhttpclient的newCall()方法将request请求传入然后执行execute()方法
newCall()内部会创建一个realCall的对象,而realCall是一个抽象类Call的实现类。
在这里插入图片描述
实现抽象类Call
在这里插入图片描述
执行型reallCall的execute()方法
在这里插入图片描述
首先先判断该任务是否执行,如果已执行则抛出“Already Executed”异常
如果任务没有执行,则由调度者执行这个任务,将任务添加到同步执行的队列里,执行任务。
在这里插入图片描述
通过调用getResponseWithInterceptorChain()这个方法得到Response相应 。下面与异步任务一起分析,此处就不再过多讲述。
当任务执行完毕后,调度者会执行finished(this)方法,将任务从队列里移除。
在这里插入图片描述

异步调用

 OkHttpClient okHttpClient=new OkHttpClient();
        Request request=new Request.Builder().build();
        try {
            okHttpClient.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {

                }

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

                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }

因为异步任务与同步任务的不同之处在于任务执行的execute()方法处,所以我们此处不讲相同的地方,着重分析execute(new Callback())方法,按住control键进入execute(new 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));
      }
      
      //调度器执行enqueue()方法,传入new AsyncCall()对象
       synchronized void enqueue(AsyncCall call) {
       //判断正在运行的异步任务数量小于最大请求数(默认为64),并且判断同一host的请求数小于同一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) {
    //创建一个核心线程数为0,非核心现场数最大为整形最大值(2的31次方-1)的线程池,空闲时间为60s
      executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
          new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;
  }
  
	//AsyncCall对象继承抽象类NamedRunnable对象,NamedRunnable对象实现了Runnable接口并实现了run()方法

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 {
    //AsyncCall 中将会重写该方法
      execute();
    } finally {
      Thread.currentThread().setName(oldName);
    }
  }

  protected abstract void execute();
}
//AsyncCall 类中重写NamedRunnable的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;
          //返回response
          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);
      }
    }
    //任务执行完后调度者调用的finished()方法
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!");
      //去等待队列查看是否还有需要执行的任务
      if (promoteCalls) promoteCalls();
      //获取正在执行的同步队列和异步队列的和
      runningCallsCount = runningCallsCount();
      idleCallback = this.idleCallback;
    }

    if (runningCallsCount == 0 && idleCallback != null) {
    如果没有课执行的任务则挂起
      idleCallback.run();
    }
  }
  //从等待队列中取任务,加入到正在执行的队列,然后线程池执行任务。
   private void promoteCalls() {
if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.

for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
  AsyncCall call = i.next();

  if (runningCallsForHost(call) < maxRequestsPerHost) {
    i.remove();
    runningAsyncCalls.add(call);
    executorService().execute(call);
  }
    if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
    }
  
  
   public synchronized int runningCallsCount() {
    return runningAsyncCalls.size() + runningSyncCalls.size();
  }

以上带大家简单分析了一下okhttp的同步调用和异步调用的基本流程相信大家对okhttp的工作原理已经有了一个简单的了解。下一节我将带大家一起分析一下okhttp的拦截器。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值