美文网首页
学习源码-OkHttp3

学习源码-OkHttp3

作者: 二十三岁的梦 | 来源:发表于2020-03-02 17:24 被阅读0次

    简单的使用流程

        OkHttpClient okhttpclient = new OkhttpClient.Builder()
                  .readTimeout(READ_TIME_OUT_VALUE, TimeUnit.SECONDS)
                  .writeTimeout(WRITE_TIME_OUT_VALUE, TimeUnit.SECONDS)
                  .build();
    
        Request.Builder builder = new Request.Builder();
        Request request = builder.url(httpUrl).get().build();
        Call call = okhttpclient.newCall(request);
        try{
            Response response = call.execute();    
        } catch (IOException e){
            //异常处理
        }
    

    从newCall出发深入源码

      /**
       * Prepares the {@code request} to be executed at some point in the future.
       */
      @Override public Call newCall(Request request) {
        return RealCall.newRealCall(this, request, false /* for web socket */);
      }
    

    我们继续查看RealCall.newRealCall

      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;
      }
    

    RealCallCall的一个实现,Responsecallexecute()方法得到的,我们接下来继续跟踪RealCallexecute方法。

      @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);
        }
      }
    
    

    方法中我们可以看到Response通过getResponseWithInterceptorChain()得到,下面是其源码:

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

    经过中间的一系列步骤,最终返回的是chain.proceed(originalRequest),那我们继续跟踪查看RealInterceptorChain并找到proceed方法的内容:

      public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
          RealConnection connection) throws IOException {
        if (index >= interceptors.size()) throw new AssertionError();
    
        calls++;
    
        // If we already have a stream, confirm that the incoming request will use it.
        if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
          throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
              + " must retain the same host and port");
        }
    
        // If we already have a stream, confirm that this is the only call to chain.proceed().
        if (this.httpCodec != null && calls > 1) {
          throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
              + " must call proceed() exactly once");
        }
    
        // Call the next interceptor in the chain.
        RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
            connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
            writeTimeout);
        Interceptor interceptor = interceptors.get(index);
        Response response = interceptor.intercept(next);
    
        // Confirm that the next interceptor made its required call to chain.proceed().
        if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
          throw new IllegalStateException("network interceptor " + interceptor
              + " must call proceed() exactly once");
        }
    
        // Confirm that the intercepted response isn't null.
        if (response == null) {
          throw new NullPointerException("interceptor " + interceptor + " returned null");
        }
    
        if (response.body() == null) {
          throw new IllegalStateException(
              "interceptor " + interceptor + " returned a response with no body");
        }
    
        return response;
      }
    

    通过上面的代码,我们发现Response response = interceptor.intercept(next);最终的请求结果是由interceptor.intercept()得到的,我们回想上一个getResponseWithInterceptorChain方法中所添加的一系列Interceptor
    我们根据变量或类名称推测建立连接的是ConnectInterceptor,我们查看一下它的具体内容:

    /** Opens a connection to the target server and proceeds to the next interceptor. */
    /** 打开一个到目标服务器的连接,并进入下一个interceptor.*/
    public final class ConnectInterceptor implements Interceptor {
      public final OkHttpClient client;
    
      public ConnectInterceptor(OkHttpClient client) {
        this.client = client;
      }
    
      @Override public Response intercept(Chain chain) throws IOException {
        RealInterceptorChain realChain = (RealInterceptorChain) chain;
        Request request = realChain.request();
        StreamAllocation streamAllocation = realChain.streamAllocation();
    
        // We need the network to satisfy this request. Possibly for validating a conditional GET.
        boolean doExtensiveHealthChecks = !request.method().equals("GET");
        HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
        RealConnection connection = streamAllocation.connection();
    
        return realChain.proceed(request, streamAllocation, httpCodec, connection);
      }
    }
    

    代码中可以看到,OkHttpClient通过RealConnection connection = streamAllocation.connection();建立了一个连接。
    我们查看RealConnection类:

    public final class RealConnection extends Http2Connection.Listener implements Connection {
      private static final String NPE_THROW_WITH_NULL = "throw with null exception";
      private static final int MAX_TUNNEL_ATTEMPTS = 21;
    
      private final ConnectionPool connectionPool;
      private final Route route;
    
      // The fields below are initialized by connect() and never reassigned.
    
      /** The low-level TCP socket. */
      private Socket rawSocket;
    
      /**
       * The application layer socket. Either an {@link SSLSocket} layered over {@link #rawSocket}, or
       * {@link #rawSocket} itself if this connection does not use SSL.
       */
      private Socket socket;
      ......
    }
    

    我们在代码中找到了比较重要的信息Socket,基本可以证明,Okhttp3的底层是Socket实现的。
    到这里不妨回忆一下我们所经历的步骤,一切都与RealInterceptorChain有很大的关系,OkhttpClient通过不断地执行它的proceed方法,反复的修饰了我们的网络请求。

    经过百度搜索,我发现这样一篇文章Okhttp3源码分析
    终于明白了它文章开篇的这个Okhttp请求流程图:

    请求流程图

    至此,我们了解了Okhttp3的简单实用,以及它的底层是通过Socket实现的,并且认识了它的拦截器链RealInterceptorChain,下一步从异步与多线程入手,再次学习Okhttp3源码。

    相关文章

      网友评论

          本文标题:学习源码-OkHttp3

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