OKHttp

作者: 小李同学今天博学了吗 | 来源:发表于2020-11-26 17:00 被阅读0次

    定义:Okhttp是对Socket的封装。有三个主要的类,Request,Response,Call
    默认使用new OkHttpClient() 创建初client对象。
    如果需要初始化网络请求的参数,如timeout,interceptor等,可以创建Builder,通过builder.build() 创建初client对象。

    三个问题

    1.请求发送到什么哪去了?框架里放到哪里了?
    请求通过execute方法发送到框架中的两个队列中去了:运行中的队列;等待中的队列,如果说运行中的队列总数小于64并且访问同一目标机器请求小于5,就进入运行队列,否则进入等待队列

    2.请求被谁处理:请求提交到运行中队列后,交给线程池来处理,直接处理请求

    3.请求是怎么被维护的:每次请求完成后,client.dispath调用finished方法,对运行中的队列和等待中的队列进行数据处理,(在符合条件的情况下,将等待中的加入到运行中队列中去)

    流程

    1.通过
    生成一个OkHttpClient client = new OkHttpClient();

    2.构建一个Request requet = new Request.Builder()
    .get().url("https:www.baidu.com").build();
    3.通过client.newCall(request)得到Call,这个call是他的子类RealCall

    4.通过call.execute(同步) 或call.enqueue(异步)启动

    A:执行Execute

    @Override public Response execute() throws IOException {
      synchronized (this) {
        if (executed) throw new IllegalStateException("Already Execu
    ted");  // (1)
        executed = true;
      }
    try { client.dispatcher().executed(this);
    // (2)
        Response result = getResponseWithInterceptorChain();
    // (3)
        if (result == null) throw new IOException("Canceled");
        return result;
      } finally {
    client.dispatcher().finished(this); // (4)
    } }
    

    1.先判断这个call是否被执行了,每个call只能被执行一次,如果要一个完成一样的call可以利用call的clone方法进行克隆

    2.利用client.dispathcer().execute(this)来进行执行,其中dispatcher.execute方法为

     synchronized void executed(RealCall call) {
        runningSyncCalls.add(call);
      }
    

    这里我刚开始没有相同,之后他加入队列后怎么调用的,后来发现在 下一个方法调用的
    3.调用getResponseWithInterceptorChain函数来获取HTTP返回的结果,这里的originalRequest就是我们的请求刚刚加入队列的是RealCall,通过chain.proceed(originalRequest)去调用

     private Response getResponseWithInterceptorChain() throws IOException {
        // Build a full stack of interceptors.
        List<Interceptor> interceptors = new ArrayList<>();
        interceptors.addAll(client.interceptors());
        interceptors.add(retryAndFollowUpInterceptor);
        interceptors.add(new BridgeInterceptor(client.cookieJar()));
        interceptors.add(new CacheInterceptor(client.internalCache()));
        interceptors.add(new ConnectInterceptor(client));
        if (!retryAndFollowUpInterceptor.isForWebSocket()) {
          interceptors.addAll(client.networkInterceptors());
        }
        interceptors.add(new CallServerInterceptor(
            retryAndFollowUpInterceptor.isForWebSocket()));
    
        Interceptor.Chain chain = new RealInterceptorChain(
            interceptors, null, null, null, 0, originalRequest);
        return chain.proceed(originalRequest);
      }
    

    4.最后还要通知dispathcer自己已经执行完毕
    client.dispatcher().finished(this);
    会执行finished(队列、call,true)
    其中这个方法是同步和异步都调用的方法,通过第三个参数,是否执行promoteCall方法具体的执行会不同,promoteCall方法

    private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
            int runningCallsCount;
            Runnable idleCallback;
            synchronized (this) {
                //TODO calls 移除队列
                if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
                //TODO 检查是否为异步请求,检查等候的队列 readyAsyncCalls,如果存在等候队列,则将等候队列加入执行队列
                if (promoteCalls) promoteCalls();
                //TODO 运行队列的数量
                runningCallsCount = runningCallsCount();
                idleCallback = this.idleCallback;
            }
            //闲置调用
            if (runningCallsCount == 0 && idleCallback != null) {
                idleCallback.run();
            }
        }
        
        private void promoteCalls() {
            //TODO 检查 运行队列 与 等待队列
            if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
            if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
    
            //TODO 将等待队列加入到运行队列中
            for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
                AsyncCall call = i.next();
                //TODO  相同host的请求没有达到最大,加入运行队列
                if (runningCallsForHost(call) < maxRequestsPerHost) {
                    i.remove();
                    runningAsyncCalls.add(call);
                    executorService().execute(call);
                }
    
                if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
            }
        }
    

    B执行Enqueue

    // RealCall.java
    @Override 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));
    }
    
     //TODO 执行异步请求
        synchronized void enqueue(AsyncCall call) {
            //TODO 同时请求不能超过并发数(64,可配置调度器调整)
            //TODO okhttp会使用共享主机即 地址相同的会共享socket
            //TODO 同一个host最多允许5条线程通知执行请求
            if (runningAsyncCalls.size() < maxRequests &&
                    runningCallsForHost(call) < maxRequestsPerHost) {
                //TODO 加入运行队列 并交给线程池执行
                runningAsyncCalls.add(call);
                //TODO AsyncCall 是一个runnable,放到线程池中去执行,查看其execute实现
                executorService().execute(call);
            } else {
                //TODO 加入等候队列
                readyAsyncCalls.add(call);
            }
        }
    
    

    相关文章

      网友评论

          本文标题:OKHttp

          本文链接:https://www.haomeiwen.com/subject/odxdektx.html