基础分析(深入分析(dispatcher、拦截器等)流程较长且更复杂,后面会单独介绍)
1. 基本请求流程
//1.创建okhttpclient和Request对象,并设置一些配置
OkHttpClient okHttpClient =new OkHttpClient().newBuilder().connectTimeout(5,TimeUnit.SECONDS).build();
Request request =new Request.Builder().url("https://www.baidu.com").get().build();
//2.将request封装成call对象
Call call = okHttpClient.newCall(request);
try {
//3.调用Call的execute()发送同步请求
Response response = call.execute();
//4.call执行异步请求
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
}catch (IOException e) {
e.printStackTrace();
}
1.1 创建okhttpclient和Request对象,并进行初始化配置:
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;
}
使用建造者
进行创建,这种模式适合于当需要初始化很多内容的时候。
注意其中dispatcher
分发器,ConnectionPool
链接池(可将我们的一个个请求理解为链接,链接池就是来管理这些链接的)主要作用:1.当请求的url是相同的时候可选择复用 2.设置链接策略。 后面会详细介绍
/**
* Policy on when async requests are executed.
*
* <p>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<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
/** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
/** Running synchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<RealCall> 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<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
dispatcher
内部维护着网络请求的线程池
,分别是readyAsyncCalls(等待中的同步请求队列)、runningAsyncCalls(请求中的异步请求队列)、runningSyncCalls(请求中的 同步请求队列)。它的代码量不多却是okhttp的核心之一。
1.2 将request封装成call对象
/**
* Prepares the {@code request} to be executed at some point in the future.
*/
@Override public Call newCall(Request request) {
return new RealCall(this, request, false /* for web socket */);
}
newcall
方法实际创建了call接口的实现类RealCall
:
RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
final EventListener.Factory eventListenerFactory = client.eventListenerFactory();
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
// TODO(jwilson): this is unsafe publication and not threadsafe.
this.eventListener = eventListenerFactory.create(this);
}
这里的OkHttpClient
,requst
引用过来了
1.3 调用Call的execute()发送同步请求
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} finally {
client.dispatcher().finished(this);
}
}
getResponseWithInterceptorChain()
这里实际上是调用了拦截器链,并通过拦截器一层层的递归,最终得到了请求返回Response
,它的内容比较多具体在okhttp源码解析--拦截器中进行分析
executed
判断同一个http请求只能执行一次,否者直接抛出异常
client.dispatcher().executed(this);
直接调用dispatcher
的executed
方法
/** Used by {@code Call#execute} to signal it is in-flight. */
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
添加到dispatcher
的runningSyncCalls
同步请求队列中,通过getResponseWithInterceptorChain()
拦截器链获得Request
并在finally
中释放当前请求。dispatcher
中被调用的finished
方法:
/** 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 <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();
}
}
在队列中移除请求,到此同步请求完毕。
1.4 异步请求enqueue
异步请求与同步请求只在最后一步调用的方法不同
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
首先和execute
方法一样判断是否是第一次请求,captureCallStackTrace()
获取网络请求的一些堆栈信息.最后一步才是真正的调用了dispatcher
的上了同步锁
的enqueue
方法,AsyncCall
继承NamedRunnable
就是一个runable
:
/**
* Runnable implementation which always sets its thread name.
*/
public abstract class NamedRunnable implements Runnable {
protected final String name;
public NamedRunnable(String format, Object... args) {
this.name = Util.format(format, args);
}
@Override public final void run() {
String oldName = Thread.currentThread().getName();
Thread.currentThread().setName(name);
try {
execute();
} finally {
Thread.currentThread().setName(oldName);
}
}
protected abstract void execute();
}
Dispatcher
中的enqueue
:
public final class Dispatcher {
private int maxRequests = 64;
private int maxRequestsPerHost = 5;
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
首先判断异步执行中的队列是否已达到最大请求数量64
&&线程数是否已到5
条,没有则添加到runningAsyncCalls
队列并通过线程池执行请求,否者添加到readyAsyncCalls
等待队列.
Dispatcher
中的线程池
:
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;
}
这里核心线程数是0(核心线程设置为0的作用在于,当线程池没有核心线程空闲一段时间后会销毁所有的线程),最大线程数量是最大值(因为上面已经设置了maxRequests(64)
了,60
代表线程执行完毕后60秒
会被销毁,所有不用担心会造成极端请求的情况)。最后 executorService().execute(call)
就调用了当前线程池中子线程的run
方法,也就是上图的NamedRunnable
中的run()
,其中NamedRunnable
的核心抽象方法execute()
在它的实现类AsyncCall
中具体实现:
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 {
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
}
通过getResponseWithInterceptorChain()
拦截链获取到了请求返回Response
在retryAndFollowUpInterceptor.isCanceled()
判断请求是否取消,
取消就调用 responseCallback
的onFailure(...)
失败方法,
否则responseCallback
的onResponse(...)
返回数据。这样一个异步请求就完成了。
注意finally中的finished,通过它dispatcher维护了队列,线程池执行下一个网络请求,具体会在下一篇进行介绍
网友评论