zoukankan      html  css  js  c++  java
  • 源码系列--OkHttp

    OkHttp官网地址:https://square.github.io/okhttp/

    用法如下:(get请求)

    package okhttp3.guide;
    
    import java.io.IOException;
    import okhttp3.OkHttpClient;
    import okhttp3.Request;
    import okhttp3.Response;
    
    public class GetExample {
      OkHttpClient client = new OkHttpClient();
    
      String run(String url) throws IOException {
        Request request = new Request.Builder()
            .url(url)
            .build();
    
        try (Response response = client.newCall(request).execute()) {
          return response.body().string();
        }
      }
    
      public static void main(String[] args) throws IOException {
        GetExample example = new GetExample();
        String response = example.run("https://raw.github.com/square/okhttp/master/README.md");
        System.out.println(response);
      }
    }

     Github下载源码地址https://github.com/square/okhttp

    4.x以上的版本都大部分更新为kotlin了,可以更改分支下载3.x的版本来看

    一。先来看第一步构造函数

    OkHttpClient client = new OkHttpClient();

    源码:

    public OkHttpClient() {
        this(new Builder());
    }

    Builder()中就是初始化了一堆变量,没啥东西

    二。来看get请求

    new Request.Builder()

    源码:找内部类Builder的构造函数

    public Builder() {
      this.method = "GET";
      this.headers = new Headers.Builder();
    }

    源码:接着找Headers的内部类Builder,暂时构造了一个变量,还没有做什么

    三。下面是执行.url方法,当然是Request内部类Builder的url方法,url暂定为String

    源码:

    public Builder url(String url) {
      if (url == null) throw new NullPointerException("url == null");
    
      // Silently replace web socket URLs with HTTP URLs.
      if (url.regionMatches(true, 0, "ws:", 0, 3)) {
        url = "http:" + url.substring(3);
      } else if (url.regionMatches(true, 0, "wss:", 0, 4)) {
        url = "https:" + url.substring(4);
      }
    
      return url(HttpUrl.get(url));
    }

    前面是加前缀,后面去到HttpUrl里去

    public static HttpUrl get(String url) {
        return new Builder().parse(null, url).build();
      }

    HttpUrl的内部类Builder的构造函数

    public Builder() {
      encodedPathSegments.add(""); // The default path is '/' which needs a trailing space.
    }

    encodedPathSegments是一个ArrayList

    HttpUrl的内部类Builder的parse方法就是一连串的参数解析,大家可以看源码

    最后一个build()方法

    public HttpUrl build() {
      if (scheme == null) throw new IllegalStateException("scheme == null");
      if (host == null) throw new IllegalStateException("host == null");
      return new HttpUrl(this);
    }

    这个HttpUrl的带参构造函数中也是一堆变量的初始化

    回到Request内部类Builder的url方法

    public Builder url(HttpUrl url) {
      if (url == null) throw new NullPointerException("url == null");
      this.url = url;
      return this;
    }

    接着是Request内部类Builder的build方法

    public Request build() {
      if (url == null) throw new IllegalStateException("url == null");
      return new Request(this);
    }

    Request的带参构造函数

    Request(Builder builder) {
      this.url = builder.url;
      this.method = builder.method;
      this.headers = builder.headers.build();
      this.body = builder.body;
      this.tags = Util.immutableMap(builder.tags);
    }

    四。接下来很重要了,是执行请求

    Response response = client.newCall(request).execute()

    OkHttpClient中的newCall方法

    @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.transmitter = new Transmitter(client, call);
      return call;
    }

    构造函数不用管,进去Transmitter中的构造函数

    public Transmitter(OkHttpClient client, Call call) {
      this.client = client;
      this.connectionPool = Internal.instance.realConnectionPool(client.connectionPool());
      this.call = call;
      this.eventListener = client.eventListenerFactory().create(call);
      this.timeout.timeout(client.callTimeoutMillis(), MILLISECONDS);
    }

    其中这个Internal.instance.realConnectionPool(client.connectionPool())可以找到OkHttpClient的static代码块执行后返回了一个RealConnectionPool

    private static final Executor executor = new ThreadPoolExecutor(0 /* corePoolSize */,
        Integer.MAX_VALUE /* maximumPoolSize */, 60L /* keepAliveTime */, TimeUnit.SECONDS,
        new SynchronousQueue<>(), Util.threadFactory("OkHttp ConnectionPool", true));

     RealConnectionPool一看就知道是0个核心线程,最大值个非核心线程的线程池;这里还出现了一个Deque双端队列,即队列的升级版,两个端口都可以进出元素,更加灵活

    最后就是RealCall的execute方法了,注意RealCall里有个内部类AsyncCall也有execute方法,注意不要搞混了

    @Override public Response execute() throws IOException {
      synchronized (this) {
        if (executed) throw new IllegalStateException("Already Executed");
        executed = true;
      }
      transmitter.timeoutEnter();
      transmitter.callStart();
      try {
        client.dispatcher().executed(this);
        return getResponseWithInterceptorChain();
      } finally {
        client.dispatcher().finished(this);
      }
    }

    client.dispatcher().executed(this)执行的是

    synchronized void executed(RealCall call) {
        runningSyncCalls.add(call);
      }

    runningSyncCalls就是我们上面提到的Deque双端队列

    下面就是最最核心的getResponseWithInterceptorChain方法

    Response getResponseWithInterceptorChain() throws IOException {
      // Build a full stack of interceptors.
      List<Interceptor> interceptors = new ArrayList<>();
      interceptors.addAll(client.interceptors());
      interceptors.add(new RetryAndFollowUpInterceptor(client));
      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, transmitter, null, 0,
          originalRequest, this, client.connectTimeoutMillis(),
          client.readTimeoutMillis(), client.writeTimeoutMillis());
    
      boolean calledNoMoreExchanges = false;
      try {
        Response response = chain.proceed(originalRequest);
        if (transmitter.isCanceled()) {
          closeQuietly(response);
          throw new IOException("Canceled");
        }
        return response;
      } catch (IOException e) {
        calledNoMoreExchanges = true;
        throw transmitter.noMoreExchanges(e);
      } finally {
        if (!calledNoMoreExchanges) {
          transmitter.noMoreExchanges(null);
        }
      }
    }

    RetryAndFollowUpInterceptor重试和跳转拦截器

    BridgeInterceptor桥接拦截器,即加请求头和去响应头

    CacheInterceptor缓存拦截器

    ConnectInterceptor连接拦截器

    CallServerInterceptor调用服务拦截器

    List添加好全部Interceptor之后,执行chain.proceed(originalRequest)来到RealInterceptorChain中的proceed方法

    public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange)
        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.exchange != null && !this.exchange.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.exchange != 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, transmitter, exchange,
          index + 1, request, call, 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 (exchange != 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;
    }

    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);

    一开始传入的index为0,就是从第一个拦截器开始执行每个拦截器的intercept方法,index逐次+1

    每个拦截器里都调用chain.proceed,这样所有的拦截器就形成链条。这里每个拦截器的作用就不讲了

    欢迎关注我的微信公众号:安卓圈

  • 相关阅读:
    mysql 初始密码 设置
    jsp基础知识(基本的语法及原理)
    hdu 2473 Junk-Mail Filter (并查集之点的删除)
    java版本的学生管理系统
    java操作数据库出现(][SQLServer 2000 Driver for JDBC]Error establishing socket.)的问题所在即解决办法
    Java学习之约瑟夫环的两中处理方法
    hdu 3367(Pseudoforest ) (最大生成树)
    hdu 1561 The more, The Better (树上背包)
    Nginx + Lua 搭建网站WAF防火墙
    长连接和短连接
  • 原文地址:https://www.cnblogs.com/anni-qianqian/p/12774332.html
Copyright © 2011-2022 走看看