美文网首页
okhttp源码分析

okhttp源码分析

作者: 24k金 | 来源:发表于2019-04-03 15:41 被阅读0次

    一、okhttp简介

    OKHttp是一个处理网络请求的开源项目,Android 当前最火热网络框架,由移动支付Square公司贡献,用于替代HttpUrlConnection和Apache HttpClient(android API23 6.0里已移除HttpClient)。现在在Android开发中最火的应用最多的联网框架毫无疑问是okhttp,目前已经大量替代了Volley、HttpUrlConnection。

    二、okhttp用法
    1)导包:

        compile 'com.squareup.okhttp3:okhttp:3.9.1'
    

    2)通过Builder类实例化客户端类OkhttpClient。

     private val client: OkHttpClient by lazy {
            OkHttpClient.Builder()
                .connectTimeout(30, TimeUnit.SECONDS)
                .readTimeout(60, TimeUnit.SECONDS)
                .writeTimeout(60, TimeUnit.SECONDS)
                .build()
        }
    

    实例化OkhttpClient时可以通过Builder类添加一系列客户端参数。
    3)通过Builder类实例化请求类Request,通过OkHttpClient的newCall方法执行请求。

     fun get(url: String, callBack: ResponseCallBack) {
            var request = Request.Builder()
                .url(Api.baseUrl + url)
                .build()
            client.newCall(request).enqueue(
                object : Callback {
                    override fun onFailure(call: Call, e: IOException) {
                        callBack?.onFail(e.toString())
                    }
    
                    override fun onResponse(call: Call, response: Response) {
                        callBack?.onSuccess(response.body()!!.string())
                    }
    
                }
            )
        }
    
        fun post(url: String, requestParams: RequestParams, callBack: ResponseCallBack) {
            var requestBody = FormBody.Builder()
            requestParams.forEach {
                requestBody.add(it.key, it.value.toString())
            }
            var request = Request.Builder()
                .url(Api.baseUrl + url)
                .post(requestBody.build())
                .build()
            client.newCall(request).enqueue(
                object : Callback {
                    override fun onFailure(call: Call, e: IOException) {
                        callBack?.onFail(e.toString())
                    }
    
                    override fun onResponse(call: Call, response: Response) {
                        callBack?.onSuccess(response.body()!!.string())
                    }
                }
            )
        }
    

    实例化Request时可以通过Builder类添加一系列请求参数(例如Header信息),这里也不进行详细描述,在分析源码时进行具体分析。
    4)同步、异步请求。execute()执行同步请求,enqueue()执行异步请求,同步请求方法返回Response,异步请求通过CallBack返回Response。

    三、源码分析
    1)OkHttpClient客户端类,主要看一下各个成员变量。

    final Dispatcher dispatcher;//请求分发器,分发执行Request
      final @Nullable Proxy proxy;//代理
      final List<Protocol> protocols;//协议,管理协议版本
      final List<ConnectionSpec> connectionSpecs;//传输层版本和连接协议
      final List<Interceptor> interceptors;//拦截器
      final List<Interceptor> networkInterceptors;//网络拦截器
      final EventListener.Factory eventListenerFactory;//请求监听器
      final ProxySelector proxySelector;//代理选择
      final CookieJar cookieJar;//cookie
      final @Nullable Cache cache;//缓存
      final @Nullable InternalCache internalCache;//内部缓存
      final SocketFactory socketFactory;//socket工厂
      final @Nullable SSLSocketFactory sslSocketFactory;//HTTPS ssl安全套接层工厂
      final @Nullable CertificateChainCleaner certificateChainCleaner;//验证证书
      final HostnameVerifier hostnameVerifier;//确认主机名
      final CertificatePinner certificatePinner;//证书链
      final Authenticator proxyAuthenticator;//代理身份验证
      final Authenticator authenticator;//本地身份验证
      final ConnectionPool connectionPool;//连接池
      final Dns dns;//DNS域名解析
      final boolean followSslRedirects;//安全套接层重定向
      final boolean followRedirects;//本地重定向
      final boolean retryOnConnectionFailure;//连接失败重试
      final int connectTimeout;//连接超时
      final int readTimeout;//读取超时
      final int writeTimeout;//写入超时
      final int pingInterval;//ping命令时间间隔
    

    可以看到所有成员变量都是final的,这样所有的变量赋值就全部交给Builder类,Builder类是OkHttpClient的静态内部类。可以通过builder()来完成设置,在不进行设置情况下会使用Builder的默认设置。

      public Builder() {
          dispatcher = new Dispatcher();
          protocols = DEFAULT_PROTOCOLS;
          connectionSpecs = DEFAULT_CONNECTION_SPECS;
          eventListenerFactory = EventListener.factory(EventListener.NONE);
          proxySelector = ProxySelector.getDefault();
          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;
          connectTimeout = 10_000;
          readTimeout = 10_000;
          writeTimeout = 10_000;
          pingInterval = 0;
        }
    

    2)Request请求信息类。成员变量如下:

      final HttpUrl url;//请求url信息
      final String method;//请求方式(post get)
      final Headers headers;//请求header
      final @Nullable RequestBody body;//请求Body
      final Object tag;//请求tag
    

    3)执行newCall()方法创建Call对象,Call接口唯一实现类是RealCall,是执行请求的真正对象。

      @Override public Call newCall(Request request) {
        return RealCall.newRealCall(this, request, false /* for web socket */);
      }
    
    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;
      }
    

    RealCall请求类的源码如下:

    final class RealCall implements Call {
      final OkHttpClient client;
      final RetryAndFollowUpInterceptor retryAndFollowUpInterceptor;//请求重定向拦截器
      private EventListener eventListener;
      final Request originalRequest;//request信息
      final boolean forWebSocket;
      // Guarded by this.
      private boolean executed;
      private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
        this.client = client;
        this.originalRequest = originalRequest;
        this.forWebSocket = forWebSocket;
        this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
      }
    
      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 Response execute() throws IOException {
        synchronized (this) {
          if (executed) throw new IllegalStateException("Already Executed");
          executed = true;
        }
        captureCallStackTrace();
        eventListener.callStart(this);
        try {
          client.dispatcher().executed(this);
          Response result = getResponseWithInterceptorChain();
          if (result == null) throw new IOException("Canceled");
          return result;
        } catch (IOException e) {
          eventListener.callFailed(this, e);
          throw e;
        } finally {
          client.dispatcher().finished(this);
        }
      }
    .....
    //异步请求
      @Override public void enqueue(Callback responseCallback) {
        synchronized (this) {
          if (executed) throw new IllegalStateException("Already Executed");
          executed = true;
        }
        captureCallStackTrace();
        eventListener.callStart(this);
        client.dispatcher().enqueue(new AsyncCall(responseCallback));
      }
    
      @Override public void cancel() {
        retryAndFollowUpInterceptor.cancel();
      }
    
      @Override public synchronized boolean isExecuted() {
        return executed;
      }
    
      @Override public boolean isCanceled() {
        return retryAndFollowUpInterceptor.isCanceled();
      }
    
      @SuppressWarnings("CloneDoesntCallSuperClone") // We are a final type & this saves clearing state.
      @Override public RealCall clone() {
        return RealCall.newRealCall(client, originalRequest, forWebSocket);
      }
    
      StreamAllocation streamAllocation() {
        return retryAndFollowUpInterceptor.streamAllocation();
      }
    
      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;
        }
    
        @Override protected void execute() {
          boolean signalledCallback = false;
          try {
            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);
          }
        }
      }
    
    //链式请求方法
      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 (!forWebSocket) {
          interceptors.addAll(client.networkInterceptors());
        }
        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);
      }
    

    先来分析同步请求,从源码中可以看到同步请求中会先通过

    client.dispatcher().executed(this);
    

    完成对请求的监听,本质上是将当前请求放入一个队列中,当请求结束之后再移除队列。

    /** Running synchronous calls. Includes canceled calls that haven't finished yet. */
      private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
    

    对于异步请求来说同样会进行请求的监听,唯一的区别在于异步请求是用两个队列完成,一个是等待请求的队列,一个是正在请求的队列。

    /** Ready async calls in the order they'll be run. */
      private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
    
      /** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
      private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
    

    最终进行网络请求是通过链式方法getResponseWithInterceptorChain来完成的。这个方法也是网络请求的精髓所在。这个方法里通过获取设置的一系列拦截器来完成网络请求工作,每个拦截器有不同的分工。最后通过构建的拦截器链调用proceed()方法完成网络请求。由于不同的拦截器分别负责网络请求中的不同工作。分析起来内容比较多,这里先不进行具体各个拦截器的源码分析。

    4)Dispatcher请求分发器,在okhttp中网络请求分发是通过Dispatcher分发器来维护的,Dispatcher控制着当前网络请求是否执行还是进入等待状态,这里涉及一些网络请求的域名等判断信息。Dispatcher类源码如下:

    public final class Dispatcher {
      private int maxRequests = 64;//最大请求数
      private int maxRequestsPerHost = 5;//最大主机名
      private @Nullable Runnable idleCallback;
      private @Nullable ExecutorService executorService;//请求线程池,核心线程0,非核心线程最大值Integer.MAX_VALUE
      private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();//异步等待队列
      private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();//异步请求队列
      private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();//同步请求队列
    .......
      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;
      }
    
      public synchronized void setMaxRequests(int maxRequests) {
        if (maxRequests < 1) {
          throw new IllegalArgumentException("max < 1: " + maxRequests);
        }
        this.maxRequests = maxRequests;
        promoteCalls();
      }
    
      public synchronized int getMaxRequests() {
        return maxRequests;
      }
      public synchronized void setMaxRequestsPerHost(int maxRequestsPerHost) {
        if (maxRequestsPerHost < 1) {
          throw new IllegalArgumentException("max < 1: " + maxRequestsPerHost);
        }
        this.maxRequestsPerHost = maxRequestsPerHost;
        promoteCalls();
      }
    
      public synchronized int getMaxRequestsPerHost() {
        return maxRequestsPerHost;
      }
    
      synchronized void enqueue(AsyncCall call) {
        if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
          runningAsyncCalls.add(call);
          executorService().execute(call);
        } else {
          readyAsyncCalls.add(call);
        }
      }
    
      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.
        }
      }
    
      private int runningCallsForHost(AsyncCall call) {
        int result = 0;
        for (AsyncCall c : runningAsyncCalls) {
          if (c.host().equals(call.host())) result++;
        }
        return result;
      }
    
      synchronized void executed(RealCall call) {
        runningSyncCalls.add(call);
      }
    
      void finished(AsyncCall call) {
        finished(runningAsyncCalls, call, true);
      }
    
      void finished(RealCall call) {
        finished(runningSyncCalls, call, false);
      }
    
      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();
        }
      }
      public synchronized List<Call> runningCalls() {
        List<Call> result = new ArrayList<>();
        result.addAll(runningSyncCalls);
        for (AsyncCall asyncCall : runningAsyncCalls) {
          result.add(asyncCall.get());
        }
        return Collections.unmodifiableList(result);
      }
      public synchronized int queuedCallsCount() {
        return readyAsyncCalls.size();
      }
      public synchronized int runningCallsCount() {
        return runningAsyncCalls.size() + runningSyncCalls.size();
      }
    }
    

    在同步请求时直接加入同步请求队列中,持有同步请求的请求引用。对于异步请求来讲,会判断当前正在执行的请求是否达到最大请求限制,并且正在执行请求的主机名是否达到个数限制,如果都没有达到限制,则立即通过线程池进行网络请求,否则放入异步等待队列。那么什么时候进行执行等待队列中的请求呢?
    在一个网络请求结束之后会调用Dispatcher的finished方法,在finished方法中会调用promoteCalls()方法来判断时候可以执行等待队列中的网络请求。

    文中demo代码:https://github.com/24KWYL/okhttp.git

    相关文章

      网友评论

          本文标题:okhttp源码分析

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