Okhttp系列文章——Okhttp是如何创建请求、响应一个请求

Okhttp系列文章目录


第一章 Okhttp是如何创建请求、响应一个请求

第二章 Okhttp中的设计模式及其应用场景、优缺点

第三章 Okhttp中的数据结构

第四章 Okhttp中的其他相关


提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档

目录

Okhttp系列文章目录

文章目录

前言

一、Okhttp是如何创建请求?

1、创建同步请求

2、创建异步请求:

二、Okhttp如何响应一个请求——源码分析

1.同步请求

2.异步请求

总结


前言

提示:这里可以添加本文要记录的大概内容:
项目中经常使用OkHttp+retrofit+rxjava进行网络框架的搭建,而Okhttp详细的运行流程及源码却基本很少分析,本文将从基础不同角度去分析Okhttp中的知识。


提示:以下是本篇文章正文内容,下面案例可供参考

一、Okhttp是如何创建请求?

OkHttp官方地址:

https://github.com/square/okhttp

引入库:

implementation("com.squareup.okhttp3:okhttp:4.9.0")

现在的版本都是基于kotlin的,如果习惯java的同学可用低版本查看java版本的源码,本文也是基于java版本源码分析的。

implementation 'com.squareup.okhttp3:okhttp:3.9.0'

1、创建同步请求

 copy官方代码:

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

从各种技术文章看到的写入,大概如下:

 OkHttpClient okHttpClient  = new OkHttpClient.Builder()
         .readTimeout(5000, TimeUnit.MILLISECONDS)
         .addInterceptor(new HttpLoggingInterceptor()) //log拦截器,暂时不用管
         .connectTimeout(15,TimeUnit.SECONDS)
         .build();
 Request request = new Request.
         Builder().
         url("http://m.baidu.com").
         addHeader("","").
         build();
Call call = okHttpClient.newCall(request);
 try {
     Response response = call.execute();
 } catch (IOException e) {
     e.printStackTrace();
 }

2、创建异步请求:

 OkHttpClient okHttpClient  = new OkHttpClient.Builder()
         .readTimeout(5000, TimeUnit.MILLISECONDS)
         .addInterceptor(new HttpLoggingInterceptor())//log拦截器,暂时不用管
         .connectTimeout(15,TimeUnit.SECONDS)
         .build();
 Request request = new Request.
         Builder().
         url("http://m.baidu.com").
         addHeader("","").
         build();
Call call = okHttpClient.newCall(request);
 call.enqueue(new Callback() {
     @Override
     public void onFailure(Call call, IOException e) {

     }

     @Override
     public void onResponse(Call call, Response response) throws IOException {

     }
 });

上述可以看到 同步和异步的区别:

//同步请求  

call.execute() ;

//异步请求

call.enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {

    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {

    }
});

 

二、Okhttp如何响应一个请求——源码分析

1.同步请求

 从call.execute() 分析,查看源码,发现是个接口:

package okhttp3;

import java.io.IOException;

public interface Call extends Cloneable {
  /**
   * @throws IOException if the request could not be executed due to cancellation, a connectivity
   * problem or timeout. Because networks can fail during an exchange, it is possible that the
   * remote server accepted the request before the failure.
   * @throws IllegalStateException when the call has already been executed.
   */
  Response execute() throws IOException;

  /**
   * @throws IllegalStateException when the call has already been executed.
   */
  void enqueue(Callback responseCallback);

  /** Cancels the request, if possible. Requests that are already complete cannot be canceled. */
  void cancel();

  /**
   * Returns true if this call has been either {@linkplain #execute() executed} or {@linkplain
   * #enqueue(Callback) enqueued}. It is an error to execute a call more than once.
   */
  boolean isExecuted();

  boolean isCanceled();

  /**
   * Create a new, identical call to this one which can be enqueued or executed even if this call
   * has already been.
   */
  Call clone();

  interface Factory {
    Call newCall(Request request);
  }
}

既然是接口,那肯定有实现,代码往前定位,发现返回的是RealCall类:

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

现在在RealCall中分析处理call.execute()了,看源码;

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

看这句 client.dispatcher().executed(this);

/** Used by {@code Call#execute} to signal it is in-flight. */
synchronized void executed(RealCall call) {
  runningSyncCalls.add(call); //队列中加入请求,后续详解
}

1.通过分发器将请求分发处理——Dispatcher分发器,有没有想到事件分发?

2.分发器怎么来的?没看到有定义?——client.dispatcher()这句看出是在OkhttpClient创建时创建的,具体怎么创建的,后续分析OkhttpClient中的设计模式(构建者模式builder)会提到。

继续分析 Dispatcher,看到我们获取的Response 已经得到了。

Response result = getResponseWithInterceptorChain(); //拦截器相关处理,后续设计模式中会分析,暂时不用管
if (result == null) throw new IOException("Canceled");
return result; //返回结果

2.异步请求

从这句出发call.enqueue(new Callback()),why? 这里是最终执行请求的地方,从这里切入是最好的。相关RealCall的流程和上面的同步请求一样,省略。重点分析异步请求:

@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)); //重点这句
}

client.dispatcher().enqueue(new AsyncCall(responseCallback)); 也是调用Dispatcher进行分发,继续跟入Dispatcher中相关代码:

synchronized void enqueue(AsyncCall call) {
//相关条件判断:满足即进入运行队列,并运行,否则 进入等待序列
// 条件:maxRequests  =64 最大请求数,maxRequestsPerHost =5 最大同一host请求数
  if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
    runningAsyncCalls.add(call); //请求加入运行队列
    executorService().execute(call);// 运行线程池,开始请求
  } else {
    readyAsyncCalls.add(call); //加入等待序列
  }
}

这里AsyncCall 显然是一个Runnable,继承 NamedRunnable,一个带命名的Runnable。感兴趣可以去查看源码。

至此这个同步、异步分析已完成,相关差异也是可以从代码中体现。


总结

提示:这里对文章进行总结:
这里只是对OkHttp的请求过程进行简单的分析,并未深入插入其他知识点,相关详细的分知识点会在其他章节讲解。

附上 Dispatcher相关源码:

/*
 * Copyright (C) 2013 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package okhttp3;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
import okhttp3.RealCall.AsyncCall;
import okhttp3.internal.Util;

/**
 * Policy on when async requests are executed.
 *
 * 

Each dispatcher uses an {@link ExecutorService} to run calls internally. If you supply your * own executor, it should be able to run {@linkplain #getMaxRequests the configured maximum} number * of calls concurrently. */ public final class Dispatcher { private int maxRequests = 64; private int maxRequestsPerHost = 5; private @Nullable Runnable idleCallback; /** Executes calls. Created lazily. */ private @Nullable ExecutorService executorService; /** Ready async calls in the order they'll be run. */ private final Deque readyAsyncCalls = new ArrayDeque<>(); /** Running asynchronous calls. Includes canceled calls that haven't finished yet. */ private final Deque runningAsyncCalls = new ArrayDeque<>(); /** Running synchronous calls. Includes canceled calls that haven't finished yet. */ private final Deque runningSyncCalls = new ArrayDeque<>(); public Dispatcher(ExecutorService executorService) { this.executorService = executorService; } public Dispatcher() { } public synchronized ExecutorService executorService() { if (executorService == null) { executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS, new SynchronousQueue(), Util.threadFactory("OkHttp Dispatcher", false)); } return executorService; } /** * Set the maximum number of requests to execute concurrently. Above this requests queue in * memory, waiting for the running calls to complete. * *

If more than {@code maxRequests} requests are in flight when this is invoked, those requests * will remain in flight. */ 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; } /** * Set the maximum number of requests for each host to execute concurrently. This limits requests * by the URL's host name. Note that concurrent requests to a single IP address may still exceed * this limit: multiple hostnames may share an IP address or be routed through the same HTTP * proxy. * *

If more than {@code maxRequestsPerHost} requests are in flight when this is invoked, those * requests will remain in flight. */ 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; } /** * Set a callback to be invoked each time the dispatcher becomes idle (when the number of running * calls returns to zero). * *

Note: The time at which a {@linkplain Call call} is considered idle is different depending * on whether it was run {@linkplain Call#enqueue(Callback) asynchronously} or * {@linkplain Call#execute() synchronously}. Asynchronous calls become idle after the * {@link Callback#onResponse onResponse} or {@link Callback#onFailure onFailure} callback has * returned. Synchronous calls become idle once {@link Call#execute() execute()} returns. This * means that if you are doing synchronous calls the network layer will not truly be idle until * every returned {@link Response} has been closed. */ public synchronized void setIdleCallback(@Nullable Runnable idleCallback) { this.idleCallback = idleCallback; } synchronized void enqueue(AsyncCall call) { if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) { runningAsyncCalls.add(call); executorService().execute(call); } else { readyAsyncCalls.add(call); } } /** * Cancel all calls currently enqueued or executing. Includes calls executed both {@linkplain * Call#execute() synchronously} and {@linkplain Call#enqueue asynchronously}. */ public synchronized void cancelAll() { for (AsyncCall call : readyAsyncCalls) { call.get().cancel(); } for (AsyncCall call : runningAsyncCalls) { call.get().cancel(); } for (RealCall call : runningSyncCalls) { call.cancel(); } } private void promoteCalls() { if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity. if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote. for (Iterator 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. } } /** Returns the number of running calls that share a host with {@code call}. */ private int runningCallsForHost(AsyncCall call) { int result = 0; for (AsyncCall c : runningAsyncCalls) { if (c.host().equals(call.host())) result++; } return result; } /** Used by {@code Call#execute} to signal it is in-flight. */ synchronized void executed(RealCall call) { runningSyncCalls.add(call); } /** Used by {@code AsyncCall#run} to signal completion. */ void finished(AsyncCall call) { finished(runningAsyncCalls, call, true); } /** Used by {@code Call#execute} to signal completion. */ void finished(RealCall call) { finished(runningSyncCalls, call, false); } private void finished(Deque 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(); } } /** Returns a snapshot of the calls currently awaiting execution. */ public synchronized List queuedCalls() { List result = new ArrayList<>(); for (AsyncCall asyncCall : readyAsyncCalls) { result.add(asyncCall.get()); } return Collections.unmodifiableList(result); } /** Returns a snapshot of the calls currently being executed. */ public synchronized List runningCalls() { List 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(); } }

你可能感兴趣的:(实战项目相关,Android第二形态,Android实践资料)