okhttp源码简单流程分析

拦截器详细解析可以看大佬简书 "https://www.jianshu.com/p/6fac73f7570f"和 "https://www.jianshu.com/p/3c740829475c"

okhttp请求流程

1:OkHttpClient okHttpClient = new OkHttpClient.Builder()

构建一个okhttpClient对象,传入你想传入的对象,不传就是默认的;

2:构建request对象

Request request = new Request.Builder()

3:okHttpClient.newCall 实际上返回的realCall类 继续调用RealCall.newRealCall

4:调用enqueue方法,传入我们需要的回调接口,而且会判断,

synchronized (this) {

if (executed) throw new IllegalStateException("Already Executed");

executed = true;

}

如果当前这个call对象已经被运行的话,则抛出异常;

5:继续调用dispatcher的enqueue方法,如果当前运行队列<64并且正在运行,访问同一个服务器地址的请求<5

就直接添加到运行队列,并且开始运行;

不然就添加到等待队列;

6:运行AsyncCall,调用它的execute方法

7:在execute方法中处理完response之后,会在finally中调用dispathcer的finished方法;

8:当当前已经处理完毕的call从运行队列中移除掉;并且调用promoteCalls方法

9:promoteCalls方法中进行判断,

如果运行队列数目大于等于64,如果等待队列里啥都没有,也直接return?

循环等待队列,

将等待队列中的数据进行移除,移除是根据运行队列中还能存放多少来决定;

移到了运行队列中,并且开始运行;

java 复制代码
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
        Request request = new Request.Builder().build();
        //newCall方法是调用RealCall的newRealCall返回一个RealCall
        Call call = okHttpClient.newCall(request);
        //执行请求
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

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

            }
        });
        //这里第二次执行会直接报IllegalStateException错误并提示Already Executed
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

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

进入call.enqueue方法

java 复制代码
@Override public void enqueue(Callback responseCallback) {
	//这个锁是为了防止重复请求 如果你同一个call enqueue多次就会直接返回Already Executed
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    eventListener.callStart(this);
    //这里的enqueue是传入任务线程AsyncCall并分配到运行队列或等待队列
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

进入enqueue方法

java 复制代码
//okhttp里执行任务分为两个队列 运行队列和等待队列
synchronized void enqueue(AsyncCall call) {
	//当运行的队列中的数值小于64, 
	//并且同时访问同一个机器目标HOST请求书小于5直接加入到运行队列不然的话就加入到等待队列
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      //这里维护着请求用的线程池
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }
java 复制代码
  public synchronized ExecutorService executorService() {
    if (executorService == null) {
    //1:核心线程数 保持在线程池中的线程数量
	//2:线程池最大可容纳的线程数  
	//3参数:当线程池中的线程数量大于核心线程数,空闲线程就会等待60s才会被终止,如果小于就会立刻停止;
      executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
          new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;
  }
java 复制代码
//这个就是队列中传入的线程NameRunnable继承自Runnable
final class AsyncCall extends NamedRunnable {
    private final Callback responseCallback;

    AsyncCall(Callback responseCallback) {
      super("OkHttp %s", redactedUrl());
      this.responseCallback = responseCallback;
    }

    String host() {
      return originalRequest.url().host();
    }

    Request request() {
      return originalRequest;
    }

    RealCall get() {
      return RealCall.this;
    }

	//这个就是Async的run方法
    @Override protected void execute() {
      boolean signalledCallback = false;
      try {
      	//getResponseWithInterceptorChain() 添加拦截器 okhttp的责任链设计也在这里
      	//response就是请求结果
        Response response = getResponseWithInterceptorChain();
        //判断重试/重定向拦截器是否被关闭
        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 {
      	//将执行完成的任务从队列中移除
        client.dispatcher().finished(this);
      }
    }
  }

添加拦截器

java 复制代码
//添加拦截器 责任链设计 
//拦截器详细解析可以看大佬简书 "https://www.jianshu.com/p/6fac73f7570f"和 "https://www.jianshu.com/p/3c740829475c"
Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());
    //重试/重定向拦截器 连接失败后进行重试、对请求结果跟进后进行重定向
    interceptors.add(retryAndFollowUpInterceptor);
    //桥拦截器:连接应用程序和服务器的桥梁,我们发出的请求会经过它的处理才能发给服务器,
    //比如设置请求内容的长度 封装header属性 host keep-live gzip header 进行基本设置,
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    //缓存拦截器 在发出请求前,先判断是否命中缓存,
    //如果命中则可以不请求,直接使用缓存的响应(默认只会对Get请求进行缓存);
    //如果未命中则进行网络请求,并将结果缓存,等待下次请求被命中。
    interceptors.add(new CacheInterceptor(client.internalCache()));
    //连接拦截器 与服务器建立连接。
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {
      interceptors.addAll(client.networkInterceptors());
    }
    //与服务器通信;封装请求数据与解析响应数据(如:HTTP报文)。
    interceptors.add(new CallServerInterceptor(forWebSocket));
	
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());
	//执行拦截器
    return chain.proceed(originalRequest);
  }

在execute方法中处理完response之后,会在finally中调用dispathcer的finished方法;

java 复制代码
//将当前已经处理完毕的call从运行队列中移除掉;并且调用promoteCalls方法
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();
    }
  }

promoteCalls方法中进行判断

java 复制代码
//如果运行队列数目大于等于64,如果等待队列里啥都没有,也直接return
//循环等待队列,
//将等待队列中的数据进行移除,移除是根据运行队列中还能存放多少来决定;
//移到了运行队列中,并且开始运行;

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.
    }
  }
相关推荐
千里马学框架19 小时前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台20 小时前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone20 小时前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc21 小时前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo1 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077001 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼1 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone1 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen1 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone1 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui