okhttp学习记录

使用的是阻塞io、进行了tcp复用(connection缓存)。

核心Interceptor工作

其核心是通过拦截器工作的。构建的链进行逐个调用。

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

缓存问题

响应结果的缓存

内部会缓存httpresponse允许缓存的结果,比如头部携带允许cache,则可以把结果缓存下来。

如果再次请求返回的是304,没有携带内容,则直接使用。

这一块和协议勾搭的比较深,没详细分析。

Connection的缓存

在内部做分发的时候会根据地址找到对应的connection,也会进行缓存,避免多次链接。

其缓冲器会默认允许有5个没有使用的连接,空闲300秒,则会回收。

只要连接都在使用,可以无限的缓存连接。获取不到缓存的连接,就会无限创建。

同步和异步

其进行http调用是通过getResponseWithInterceptorChain这个方法。

同步调用,则直接在提交之后到线程池之后,直接获取结果,进行原地阻塞。

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

异步调用,则是提交到线程池之后,在线程运行的时候获取到结果,然后调用回调函数,在进行处理。

其使用了核心线程池大小是0,队列无限大的线程池。所以会一直有一个非核心线程在运行。

// 先enqueue 进行队列中。
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));
  }

// 在线程池执行的时候去获取结果
  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);
      }
    }
  }

返回结果和Http响应关联

通过CallServerInterceptor进行网络交互

正常的网络通信结果是不知道针对哪个请求进行响应的。如何在众多响应字节中找到对应的请求结果。

首先在连接复用的时候是会对connection进行引用计数,没有引用才可以获取。有引用不行,所以不会存在一个连接同时发送多个http请求的问题。

在http请求返回的时候根据http协议,先对header进行解析,以换行符结尾。然后对body进行解析,以header中的content-length进行解析,从而保证获取正确的http响应。

使用demo

同步get

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

同步post

 public static final MediaType JSON
      = MediaType.parse("application/json; charset=utf-8");

  OkHttpClient client = new OkHttpClient();

  String post(String url, String json) throws IOException {
    RequestBody body = RequestBody.create(JSON, json);
    Request request = new Request.Builder()
        .url(url)
        .post(body)
        .build();
    try (Response response = client.newCall(request).execute()) {
      return response.body().string();
    }
  }

  String bowlingJson(String player1, String player2) {
    return "{'winCondition':'HIGH_SCORE',"
        + "'name':'Bowling',"
        + "'round':4,"
        + "'lastSaved':1367702411696,"
        + "'dateStarted':1367702378785,"
        + "'players':["
        + "{'name':'" + player1 + "','history':[10,8,6,7,8],'color':-13388315,'total':39},"
        + "{'name':'" + player2 + "','history':[6,10,5,10,10],'color':-48060,'total':41}"
        + "]}";
  }

  public static void main(String[] args) throws IOException {
    PostExample example = new PostExample();
    String json = example.bowlingJson("Jesse", "Jake");
    String response = example.post("http://www.roundsapp.com/post", json);
    System.out.println(response);
  }

异步get

OkHttpClient client = new OkHttpClient();

  String run(String url) throws IOException {
    Request request = new Request.Builder()
        .url(url)
        .build();

    try (Response response = client.newCall(request).enqueue(() ->{
      // 此处要重写callback的方法
    ) {
      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);
  }

注:

并发调用从连接池获取不到连接的话,会无限创建连接。

public ConnectionPool() {
  // 5代表允许的最大空闲的连接,这个的意思是我会有一个数字关联connection是否在使用
  // 如果没有使用的数字超过了5个,则会进行回收
  // 6代表是对没有使用的连接 6分钟回收,和5没啥关系
  this(5, 6, TimeUnit.MINUTES);
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值