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.
    }
  }
相关推荐
阿巴斯甜7 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker8 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq95279 小时前
Andorid Google 登录接入文档
android
黄林晴10 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab1 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_1 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android