博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
OkHttp工作流程
阅读量:5906 次
发布时间:2019-06-19

本文共 6632 字,大约阅读时间需要 22 分钟。

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
    (), 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 
    void finished(Deque
    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
    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流中读取返回信息

转载于:https://juejin.im/post/5c0087e0f265da61461de41a

你可能感兴趣的文章
《Servlet和JSP学习指南》一1.3 编写基础的Servlet应用程序
查看>>
技术报告:APT组织Wekby利用DNS请求作为C&C设施
查看>>
抢先布局5G:联发科加入中国移动5G联合创新中心
查看>>
云服务鼻祖来告诉你99%的创业者不知道的事
查看>>
WFA发布LTE-U共存测试计划 Wi-Fi和LTE-U将公平共享频谱
查看>>
快递单信息泄露惊人 隐形面单能拯救你的隐私吗?
查看>>
移动“村务云”创新“互联网+无线政务”新方式
查看>>
大数据企业落户山西将获重金奖励
查看>>
新品、新投资方两大悬念待解 海云捷迅发布会受关注
查看>>
Kubuntu 15.10 高清截图欣赏
查看>>
30 岁: 程序员心中永远的痛?
查看>>
《C++ 黑客编程揭秘与防范(第2版)》—第6章6.7节打造一个密码显示器
查看>>
时间到底是怎么弯曲的?
查看>>
《游戏编程模式》一1.7 准备出发
查看>>
讨喜的隔离可变性(十二)基于角色模型的局限性和小结
查看>>
《Nmap渗透测试指南》—第10章10.2节Zenmap基本配置
查看>>
《C语言点滴》一导读
查看>>
机器人系统设计与制作:Python语言实现3.2 习题
查看>>
《趣学JavaScript——教孩子学编程》——2.2 变量
查看>>
《SQL学习指南(第2版)(修订版)》——1.2 什么是SQL
查看>>