OkHttp源码流程分析

版权声明:欢迎转载 有不明白的 写的不正确的地方 欢迎一起讨论 谢谢 https://blog.csdn.net/qq_27744987/article/details/82842519
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
Request request = new Request.Builder().build();
Call newCall = okHttpClient.newCall(request);
//同步请求
//Response response = newCall.execute();
//异步请求
newCall.enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
    }
});
  • 异步请求接口的Callback中的成功失败接口回调是运行在子线程

execute()总结

public Response execute() throws IOException {
    synchronized (this) {
      //判断当前call是否执行过,是的话抛异常
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    eventListener.callStart(this);
    try {
      //将当前call添加到Dispatcher正在执行的任务队列
      client.dispatcher().executed(this);
      //通过一系列拦截器链做网络请求,拿到response
      Response result = getResponseWithInterceptorChain();
      if (result == null) throw new IOException("Canceled");
      return result;
    } catch (IOException e) {
      eventListener.callFailed(this, e);
      throw e;
    } finally {
      //从正在执行的任务队列中移除当前call
      client.dispatcher().finished(this);
    }
  }
  • 判断当前call是否执行过,是的话抛异常
  • 将当前call添加到Dispatcher正在执行的任务队列
  • 通过一系列拦截器链做网络请求,拿到response
  • 从正在执行的任务队列中移除当前call

异步enqueue()总结

> RealCall类enqueue()方法

public void enqueue(Callback responseCallback) {
    synchronized (this) {
      //判断当前call是否执行过,是的话抛异常
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    eventListener.callStart(this);
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }
  • 判断当前call是否执行过,是的话抛异常

  • 将callBack封装成一个AsyncCall对象

    • AsyncCall继承NamedRunnable,定义在RealCall中的内部类
    • NamedRunnable是Runnable的一个实现类,Runnable的run()方法内部会调用到自己类中的一个抽象方法execute(),最终实现在AsyncCall中
      > AsyncCall类execute()方法具体实现
      
      protected void execute() {
            boolean signalledCallback = false;
            try {
              //通过一系列拦截器链做网络请求,拿到response
              Response response = getResponseWithInterceptorChain();
              //通过判断重定向重试拦截器是否被取消了,是的话就调用responseCallback.onFailure()
              if (retryAndFollowUpInterceptor.isCanceled()) {
                signalledCallback = true;
                responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
              } else {
                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 {
                //发生异常也会调用失败回调
                eventListener.callFailed(RealCall.this, e);
                responseCallback.onFailure(RealCall.this, e);
              }
            } finally {
              //将当前请求call对象从正在运行任务队列中移除
              client.dispatcher().finished(this);
            }
          }
      
  • 调用client.dispatcher().enqueue()

    > Dispatcher类enqueue()方法
    
    //判断正在运行异步任务队列大小是否小于最大请求数(64)并且通过runningCallsForHost()方法获取到正在运行的异步任务队列中和当前call所要请求的主机一样的调用数来判断是否小于最大请求主机数(5)
    //如果满足上述条件 则将当前call添加到正在运行异步任务队列中,否则添加到等待异步任务队列
    synchronized void enqueue(AsyncCall call) {
        if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
          //添加到异步任务队列
          runningAsyncCalls.add(call);
          //开启线程池执行当前call
          //executorService()方法内部会判断线程池是否已经创建,是的话直接返回,否的话创建线程池
          //execute() 将来某个时候执行给定的任务,任务可以在新线程或现有池中已存在的线程执行
          //其实就是把AsyncCall(线程的实现类)对象放到线程池中,最后真正执行的就是AsyncCall对象的execute()方法
          executorService().execute(call);
        } else {
          //添加到异步等待任务队列
          readyAsyncCalls.add(call);
        }
      }
    

Dispatcher

  • 什么是Dispatcher?

    dispatcher的作用是维护请求的状态,并维护一个线程池,用于执行请求

  • Dispatcher的异步请求为什么要维护两个任务队列?

    Dispatcher 生产者

    ExecutorService 消费者池

    • runningAsyncCalls 正在执行异步请求队列,包含没有执行完的请求但已经被取消了
    • readyAsyncCalls 就绪状态异步请求队列
    • executorService 执行请求的线程池
  • executorService()

    public synchronized ExecutorService executorService() {
        if (executorService == null) {
          //corePoolSize:0 核心线程数.0的话就表示在空闲一段时间(keepAliveTime)后,会将全部线程销毁
          //maximumPoolSize:Integer.MAX_VALUE 线程池允许创建最大线程数;理论上设置MAX_VALUE可以无限扩充创建线程,由于OKHttp有maxRequests(64)限制,实际并不能无限创建线程
          //keepAliveTime:60 空闲线程最大存活时间.当我们的线程数大于核心线程数,多余的空闲线程最大存活时间
          //3个参数含义:当线程池中任务执行完毕之后,会在60秒之后相继关闭所有空闲线程
          executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
              new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
        }
        return executorService;
      }
    
  • 移除任务call

    同步请求和异步请求在拿到Response之后都会调用finished()方法

    > 以下方法全是在Dispatcher类中
    
    //异步请求
    void finished(AsyncCall call) {
        finished(runningAsyncCalls, call, true);
    }
    //同步请求
    void finished(RealCall call) {
        finished(runningSyncCalls, call, false);
    }
    
    private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
        int runningCallsCount;
        Runnable idleCallback;
        synchronized (this) {
          //从当前任务队列中移除当前call
          if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
          //调整异步请求任务队列 只有异步请求才会执行promoteCalls()
          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);
          }
          //如果正在执行异步队列中数量大于等于最大请求数(64),直接结束调度
          if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
        }
    }
    

拦截器

拦截器是OkHttp中提供一种强大机制,它可以实现网络监听、请求以及响应重写、请求失败重试等功能

  • RetryAndFollowUpInterceptor

    重试,失败重定向拦截器

    • 创建StreamAllocation对象
    • 调用RealInterceptorChain.proceed()方法进行网络请求
    • 根据异常结果获取响应结果判断是否要重新请求
    • 调用下一个拦截器,对Response进行处理
  • BridgeInterceptor

    桥接适配拦截器,处理请求缺少必要的http请求头相关信息

    • 负责将用户构建的一个Request请求转化为能够进行网络访问的请求
    • 将这个符合网络请求的Request进行网络请求
    • 将网络请求回来的响应Response转化为用户可用的Response
  • CacheInterceptor

    缓存拦截器,通过DiskLRUCache实现缓存存取,OkHttp内部维护清理线程池,会自动清理缓存文件

  • ConnectInterceptor

    连接拦截器,建立可用的连接

    • ConnectInterceptor获取Interceptor传递过来的StreamAllocation,streamAllocation.newStream()
    • 将刚才创建用于网络IO的RealConnection对象,以及对于与服务器交互最为关键的HttpCodec等对象传递后面的Interceptor

    newStream()总结

    • 获取到一个RealConnection
    • 选择不同的链接方式
  • CallServerInterceptor

    • 将http请求写入到网络的IO流当中,从网络io流中读取返回信息

猜你喜欢

转载自blog.csdn.net/qq_27744987/article/details/82842519