美文网首页
Okhttp原理

Okhttp原理

作者: 杰奎琳子 | 来源:发表于2020-07-27 20:42 被阅读0次

// 构建okHttpClient,相当于请求的客户端,Builder设计模式

OkHttpClient okHttpClient = new OkHttpClient.Builder()

.readTimeout(5, TimeUnit.SECONDS)

.build();

        // 构建一个请求体,同样也是Builder设计模式

        Request request = new Request.Builder()

        .url("http://www.baidu.com")

        .build();

        //  生成一个Call对象,该对象是接口类型,后面会说

        Call call = okHttpClient.newCall(request);

        try {

            //  拿到Response

            Response response = call.execute();

            Log.i("TAG",response.body().string());

        } catch (IOException e) {

        }

通过Builder模式创建OkHttpClient对象和Request对象

调用OkHttpClient的newCall方法,获取一个Call对象,参数是Request

调用execute方法获取一个Respone

首先Builder是OkHttpClient一个静态内部类,在Builder的构造函数中进行了一系列的初始化操作。包括了对Dispatcher与ConnectionPool初始化。

Dispatcher分发器,负责将每一次Requst进行分发,压栈到自己的线程池,并通过调用者自己不同的方式进行异步和同步处理。

ConnectionPool是一个连接池对象,它可以用来管理连接对象,从它的构造方法中可以看到连接池的默认空闲连接数为5个,keepAlive时间为5分钟。

Call call = okHttpClient.newCall(request);

实际上创建的对象是Call的实现类RealCall 对象。

  Response response = call.execute();

这里其实是调用的是RealCall类的execute()方法。

@Override public Response execute() throws IOException {

    synchronized (this) {

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

      executed = true;

    }

    captureCallStackTrace();

    timeout.enter();

    eventListener.callStart(this);

    try {

      client.dispatcher().executed(this);//通过此方法将call对象放入到同步请求队列中。

      Response result = getResponseWithInterceptorChain();

      if (result == null) throw new IOException("Canceled");

      return result;

    } catch (IOException e) {

      e = timeoutExit(e);

      eventListener.callFailed(this, e);

      throw e;

    } finally {

      client.dispatcher().finished(this);

    }

}

在同步请求中Dispatcher主要负责了两件事,同步请求的保存和移除。

异步请求时client.newCall(request).enqueue();

RealCall.java

@Override public void enqueue(Callback responseCallback) {

    //TODO 不能重复执行

    synchronized (this) {

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

      executed = true;

    }

    captureCallStackTrace();

    eventListener.callStart(this);

    //TODO 交给 dispatcher调度器 进行调度

    client.dispatcher().enqueue(new AsyncCall(responseCallback));

  }

利用dispatcher调度器,来进行实际的执行

client.dispatcher().enqueue(new AsyncCall(responseCallback));

在上面的OkHttpClient.Builder可以看出 已经初始化了Dispatcher。

//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);

        }

    }

Dispatcher将call 加入到队列中,然后通过线程池来执行call。

public synchronized ExecutorService executorService() {

        if (executorService == null) {

            //TODO 线程池的相关概念 需要理解

            //TODO 核心线程 最大线程 非核心线程闲置60秒回收 任务队列

            executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,

                    new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher",

                    false));

        }

        return executorService;

    }

这里的call是AsyncCall,然后final class AsyncCall extends NamedRunnable

final class AsyncCall extends NamedRunnable {

    @Override protected void execute() {

      boolean signalledCallback = false;

      try {

        //TODO 责任链模式

        //TODO 拦截器链  执行请求

        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 {

        //TODO 移除队列

        client.dispatcher().finished(this);

      }

    }

  }

通过getResponseWithInterceptorChain(); 然后通过回调将Response返回给用户。

client.dispatcher().finished(this); 通过调度器移除队列,并且判断是否存在等待队列,如果存在,检查执行队列是否达到最大值,如果没有将等待队列变为执行队列。这样也就确保了等待队列被执行。

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.

        }

    }

getResponseWithInterceptorChain()核心:

//TODO 核心代码 开始真正的执行网络请求

  Response getResponseWithInterceptorChain() throws IOException {

    // Build a full stack of interceptors.

    //TODO 责任链

    List<Interceptor> interceptors = new ArrayList<>();

    //TODO 在配置okhttpClient 时设置的intercept 由用户自己设置

    interceptors.addAll(client.interceptors());

    //TODO 负责处理失败后的重试与重定向

    interceptors.add(retryAndFollowUpInterceptor);

    //TODO 负责把用户构造的请求转换为发送到服务器的请求 、把服务器返回的响应转换为用户友好的响应 处理 配置请求头等信息

    //TODO 从应用程序代码到网络代码的桥梁。首先,它根据用户请求构建网络请求。然后它继续呼叫网络。最后,它根据网络响应构建用户响应。

    interceptors.add(new BridgeInterceptor(client.cookieJar()));

    //TODO 处理 缓存配置 根据条件(存在响应缓存并被设置为不变的或者响应在有效期内)返回缓存响应

    //TODO 设置请求头(If-None-Match、If-Modified-Since等) 服务器可能返回304(未修改)

    //TODO 可配置用户自己设置的缓存拦截器

    interceptors.add(new CacheInterceptor(client.internalCache()));

    //TODO 连接服务器 负责和服务器建立连接 这里才是真正的请求网络

    interceptors.add(new ConnectInterceptor(client));

    if (!forWebSocket) {

      //TODO 配置okhttpClient 时设置的networkInterceptors

      //TODO 返回观察单个网络请求和响应的不可变拦截器列表。

      interceptors.addAll(client.networkInterceptors());

    }

    //TODO 执行流操作(写出请求体、获得响应数据) 负责向服务器发送请求数据、从服务器读取响应数据

    //TODO 进行http请求报文的封装与请求报文的解析

    interceptors.add(new CallServerInterceptor(forWebSocket));

    //TODO 创建责任链

    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,

        originalRequest, this, eventListener, client.connectTimeoutMillis(),

        client.readTimeoutMillis(), client.writeTimeoutMillis());

    //TODO 执行责任链

    return chain.proceed(originalRequest);

  }

流程简述:

(1)、当我们通过OkhttpClient创立一个Call,并发起同步或者异步请求时;

(2)、okhttp会通过Dispatcher对我们所有的RealCall(Call的具体实现类)进行统一管理,并通过execute()及enqueue()方法对同步或者异步请求进行解决;

(3)、execute()及enqueue()这两个方法会最终调用RealCall中的getResponseWithInterceptorChain()方法,从阻拦器链中获取返回结果;

(4)、阻拦器链中,依次通过RetryAndFollowUpInterceptor(重定向阻拦器)、BridgeInterceptor(桥接阻拦器)、CacheInterceptor(缓存阻拦器)、ConnectInterceptor(连接阻拦器)、CallServerInterceptor(网络阻拦器)对请求依次解决,与服务的建立连接后,获取返回数据,再经过上述阻拦器依次解决后,最后将结果返回给调用方。

相关文章

网友评论

      本文标题:Okhttp原理

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