美文网首页
Okhttp的浅层架构分析

Okhttp的浅层架构分析

作者: Android程序员老鸦 | 来源:发表于2021-06-20 20:33 被阅读0次

    Okhttp的浅层架构分析
    Okhttp的责任链模式和拦截器分析
    Okhttp之RetryAndFollowUpInterceptor拦截器分析
    Okhttp之BridgeInterceptor拦截器分析
    Okhttp之CacheInterceptor拦截器分析
    Okhttp之ConnectInterceptor拦截器分析
    Okhttp之网络连接相关三大类RealConnection、ConnectionPool、StreamAllocation
    Okhttp之CallServerInterceptor拦截器分析
    浅析okio的架构和源码实现

    Okhttp作为现在最受欢迎的网络框架,没有之一,为什么会这么有说服力的让开发者们都认可呢,带着这些疑问我们看看它的源码是怎么设计的。

    首先看看okhttp的异步Get请求:

            //bulider模式创建一个默认的OkhttpClient对象
            var client = OkHttpClient.Builder().build()
            //仍然是builder模式创建Request对象
            var request = Request.Builder().url("https://www.baidu.com").get().build()
            //调用OkHttpClient的newCall()方法新建了一个RealCall对象
            val newCall = client.newCall(request)
            //调用RealCall的enqueue()方法开启异步线程访问,传入回调接口
            newCall.enqueue(object : Callback {
                override fun onFailure(call: Call, e: IOException) {
                }
    
                override fun onResponse(call: Call, response: Response) {
                }
            })
    

    我们就一步步跟着看看它每一个步骤都是怎么实现的,先看看OkHttpClient的主要代码,这里就只先关注以上步骤出现的相关代码,先把流程梳理清楚,所以就看看它的Builder内部类:

      public static final class Builder {
        Dispatcher dispatcher; //异步调用分配者,通过线程池,来分别调用
        @Nullable Proxy proxy;
        List<Protocol> protocols;
        List<ConnectionSpec> connectionSpecs;
        final List<Interceptor> interceptors = new ArrayList<>();// 自定义拦截器 集合
        final List<Interceptor> networkInterceptors = new ArrayList<>(); //网络拦截器 集合
        EventListener.Factory eventListenerFactory;
        ProxySelector proxySelector;
        CookieJar cookieJar;    //cookie
        @Nullable Cache cache; //缓存
        @Nullable InternalCache internalCache;
        SocketFactory socketFactory;
        @Nullable SSLSocketFactory sslSocketFactory;
        @Nullable CertificateChainCleaner certificateChainCleaner;
        HostnameVerifier hostnameVerifier;
        CertificatePinner certificatePinner;
        Authenticator proxyAuthenticator;
        Authenticator authenticator;
        ConnectionPool connectionPool; //线程池,所有的有效链接都会保存在这里,也优先在这里查找是否有可用的链接
        Dns dns;
        boolean followSslRedirects;
        boolean followRedirects;
        boolean retryOnConnectionFailure;
        //各种超时时间设置,看名字就知道是干啥的啦
        int callTimeout; 
        int connectTimeout;
        int readTimeout;
        int writeTimeout;
        int pingInterval;
    
      public Builder() {
          dispatcher = new Dispatcher();
          protocols = DEFAULT_PROTOCOLS;
          connectionSpecs = DEFAULT_CONNECTION_SPECS;
          eventListenerFactory = EventListener.factory(EventListener.NONE);
          proxySelector = ProxySelector.getDefault();
          if (proxySelector == null) {
            proxySelector = new NullProxySelector();
          }
          cookieJar = CookieJar.NO_COOKIES;
          socketFactory = SocketFactory.getDefault();
          hostnameVerifier = OkHostnameVerifier.INSTANCE;
          certificatePinner = CertificatePinner.DEFAULT;
          proxyAuthenticator = Authenticator.NONE;
          authenticator = Authenticator.NONE;
          connectionPool = new ConnectionPool();
          dns = Dns.SYSTEM;
          followSslRedirects = true;
          followRedirects = true;
          retryOnConnectionFailure = true;
          callTimeout = 0;
          connectTimeout = 10_000;
          readTimeout = 10_000;
          writeTimeout = 10_000;
          pingInterval = 0;
        }
    
        ...省略其他代码
    }
    

    主要的一些属性都注释了,其他的暂时不深究,这里默认初始化的时候重点关注Dispatcher类,到时候会用到它。接下来看看newCall()方法:

     public Call newCall(Request request) {
        return RealCall.newRealCall(this, request, false /* for web socket */);
      }
    

    来看看RealCall类

    final class RealCall implements Call {
      final OkHttpClient client;
      final RetryAndFollowUpInterceptor retryAndFollowUpInterceptor;
      final AsyncTimeout timeout;
    
    //静态方法,传入了client,request等参数
    static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
        // Safely publish the Call instance to the EventListener.
        RealCall call = new RealCall(client, originalRequest, forWebSocket);
        call.eventListener = client.eventListenerFactory().create(call);
        return call;
      }
       @Override 
      public void enqueue(Callback responseCallback) {
        synchronized (this) {
          if (executed) throw new IllegalStateException("Already Executed");
          executed = true;
        }
        captureCallStackTrace();
        eventListener.callStart(this);
        //OkhttpClient里的那个成员变量dispatcher
        client.dispatcher().enqueue(new AsyncCall(responseCallback));
      }
    }
    

    我们知道okhttp的异步请求是调用了enqueue()方法,在这个方法里我们看到了之前提到的OkhttpClient里的那个成员变量dispatcher,最终是调用了它的enqueue()方法,那我们来看看Dispatcher的enqueue()方法:

    public final class Dispatcher {
      private int maxRequests = 64;
      private int maxRequestsPerHost = 5;
      private @Nullable Runnable idleCallback;
    
    //熟悉的线程池
      private @Nullable ExecutorService executorService;
      //准备好的要执行的任务
      private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
    
    
     void enqueue(AsyncCall call) {
        synchronized (this) {
          readyAsyncCalls.add(call);
        }
        promoteAndExecute();
      }
    }
    
      private boolean promoteAndExecute() {
        assert (!Thread.holdsLock(this));
    
        List<AsyncCall> executableCalls = new ArrayList<>();
        boolean isRunning;
      //准备可执行的任务
        synchronized (this) {
          for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
            AsyncCall asyncCall = i.next();
            if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
            if (runningCallsForHost(asyncCall) >= maxRequestsPerHost) continue; // Host max capacity.
            i.remove();
            executableCalls.add(asyncCall);
            runningAsyncCalls.add(asyncCall);
          }
          isRunning = runningCallsCount() > 0;
        }
      //遍历执行可执行的任务
        for (int i = 0, size = executableCalls.size(); i < size; i++) {
          AsyncCall asyncCall = executableCalls.get(i);
          //放到线程池里去执行,这个executeOn()是asyncCall的方法,executorService()方法就是得到一个线程池,AsyncCall类,这个类肯定是个ruannable
          asyncCall.executeOn(executorService());
        }
        return isRunning;
      }
      public synchronized ExecutorService executorService() {
        if (executorService == null) {
          executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
              new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
        }
        return executorService;
      }
      
    

    AsyncCall类,前面提到这个类肯定是个ruannable,看看源码:

    //带名称的Runnable ,方便管理标记,AsyncCall继承了这个类
    public abstract class NamedRunnable implements Runnable {
      protected final String name;
    
      public NamedRunnable(String format, Object... args) {
        this.name = Util.format(format, args);
      }
    
      @Override public final void run() {
        String oldName = Thread.currentThread().getName();
        Thread.currentThread().setName(name);
        try {
          //子类实现,最终的执行代码放在这里
          execute();
        } finally {
          Thread.currentThread().setName(oldName);
        }
      }
    
      protected abstract void execute();
    }
    
    //AsyncCall,实现的了NamedRunnable 
      final class AsyncCall extends NamedRunnable {
        private final Callback responseCallback;
    
        AsyncCall(Callback responseCallback) {
          super("OkHttp %s", redactedUrl());
          this.responseCallback = responseCallback;
        }
    //上面dispatcher调用的方法
    void executeOn(ExecutorService executorService) {
          assert (!Thread.holdsLock(client.dispatcher()));
          boolean success = false;
          try {
            //最终的执行步骤,线程池的execute()方法,注意executorService是执行了AsyncCall ,也就是会执行下面的execute() 方法,不要晕
            executorService.execute(this);
            success = true;
          } catch (RejectedExecutionException e) {
            InterruptedIOException ioException = new InterruptedIOException("executor rejected");
            ioException.initCause(e);
            eventListener.callFailed(RealCall.this, ioException);
            responseCallback.onFailure(RealCall.this, ioException);
          } finally {
            if (!success) {
              client.dispatcher().finished(this); // This call is no longer running!
            }
          }
        }
         //最终的请求提交,可以看到getResponseWithInterceptorChain()方法拿到response ,这就是开始了责任链调用模式,后面详细分析
        @Override
       protected void execute() {
          boolean signalledCallback = false;
          timeout.enter();
          try {
           //开启责任链调用拿到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) {
            e = timeoutExit(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);
          }
        }
      }
    

    至此,okhttp的大致异步调用的大概结构了解了,说到底还是把请求任务封装成runnable放在线程池里去执行,当然这只是整体脉络,要继续了解它是怎么得到response响应的,就要开始聊聊它著名的责任链模式和拦截器的设计了,篇幅有限我们放到下篇来讲。

    相关文章

      网友评论

          本文标题:Okhttp的浅层架构分析

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