OKHttp

2020-11-26  本文已影响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);
        }
    }

上一篇下一篇

猜你喜欢

热点阅读