okhttp3源码分析:网络请求过程

前言

okhttp作为一个强大的网络请求框架,网络请求是它的核心。okhttp的网络请求有两种:同步请求和异步请求。本文将基于okhttp-3.10.0分析这两种请求的过程。

预备知识

下面是一些预备的知识,在网络请求过程中,会用到一些类,所以先分析一下这些类。

OkHttpClient、Request和Call的创建

在使用okhttp的时候,需要先创建OkHttpClient、Request和Call对象。

创建OkHttpClient

首先是OkHttpClient的创建,有两种方式创建OkHttpClient。

  1. 默认方式
    1
    OkHttpClient okHttpClient = new OkHttpClient();

这种方式调用了无参构造器

1
2
3
4
5
6
7
8
9
10
11
public OkHttpClient() {
this(new Builder());
}

OkHttpClient(Builder builder) {
//参数设置为builder提供的默认值
this.dispatcher = builder.dispatcher;
this.proxy = builder.proxy;
this.protocols = builder.protocols;
...
}

这种方式下,参数都设置为Builder提供的默认值

  1. Builder模式
    1
    2
    3
    4
    OkHttpClient okHttpClient = new OkHttpClient.Builder()
    .connectTimeout(10, TimeUnit.SECONDS)
    .readTimeout(10, TimeUnit.SECONDS)
    .build();

OkHttpClient.Builder的build方法:

1
2
3
public OkHttpClient build() {
return new OkHttpClient(this);
}

第二种是利用Builder模式创建,通过这种方式创建,可以在创建Builder时链式添加自定义的参数。例如上面自定义了连接超时时间、读取超时时间。

创建Request

创建Request只有一种方式,那就是通过Builder模式,例如:

1
2
3
Request request = new Request.Builder()
.url("https://www.wanandroid.com/project/tree/json")
.build();

这是因为Request没有提供共有的构造器,需要通过Request.Builder的build方法创建Request实例:

1
2
3
4
5
6
7
8
9
10
11
12
  public Request build() {
if (url == null) throw new IllegalStateException("url == null");
return new Request(this);
}

Request(Builder builder) {
this.url = builder.url;
this.method = builder.method;
this.headers = builder.headers.build();
this.body = builder.body;
this.tag = builder.tag != null ? builder.tag : this;
}

创建Call

Call是一个接口,它的唯一实现类是RealCall,通过OkHttpClient的newCall方法创建:

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

之后调用RealCall的newRealCall方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
RealCall call = new RealCall(client, originalRequest, forWebSocket);
//创建EventListener,外界可通过EventListener的回调在某个节点做相关操作
call.eventListener = client.eventListenerFactory().create(call);
return call;
}

private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
}

在创建RealCall时主要是初始化了一些实例。

Dispatcher

Dispatcher也是一个比较关键的类,它主要用于保存和移除异步请求和同步请求,并控制它们的执行,主要成员变量如下:

成员变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//最大并发请求数
private int maxRequests = 64;
//每个主机的最大请求数
private int maxRequestsPerHost = 5;

//执行异步请求的线程池
private @Nullable ExecutorService executorService;

//将要运行的异步请求队列
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();

//正在运行的异步请求队列
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();

//正在运行的同步请求队列
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

构造方法

Dispatcher有两个构造方法,其中一个构造方法可以指定执行异步请求的线程池:

1
2
3
public Dispatcher(ExecutorService executorService) {
this.executorService = executorService;
}

另一个构造方法没有指定线程池,使用默认的线程池,且是在第一次进行请求时才初始化线程池:

1
2
3
4
5
6
7
8
9
10
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;
}

默认的线程池属于CachedThreadPool,适合执行大量且耗时较少的任务。

网络请求过程分析

同步请求

RealCall#execute

在进行同步请求时,会调用RealCall的execute方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Override public Response execute() throws IOException {
synchronized (this) {
//先判断该Call是否被执行,一个Call只能执行一次
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this); //回调,外界可在这时做相关操作
try {
//获得OkHttpClient中的Dispatcher对象,调用Dispatcher的executed方法
//将当前请求加入同步请求队列
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);
}
}

该方法先判断Call是否被执行过,一个Call只能执行一次。之后会调用Dispatcher的executed方法将Call加入同步请求队列,最后进行一系列拦截操作,并获取返回结果。

先看Dispatcher的executed方法:

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

该方法将RealCall加入同步请求队列。

RealCall#getResponseWithInterceptorChain

接下来RealCall会调用getResponseWithInterceptorChain方法,该方法很重要,其实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
 Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();

//在配置OkHttpClient时设置的interceptors
interceptors.addAll(client.interceptors());

//RetryAndFollowUpInterceptor:负责失败重试和重定向
interceptors.add(retryAndFollowUpInterceptor);

//BridgeInterceptor:负责把用户请求转换为发送到服务器的请求,
//并把服务器的响应转化为用户需要的响应
interceptors.add(new BridgeInterceptor(client.cookieJar()));

//CacheInterceptor:负责读取缓存、更新缓存
interceptors.add(new CacheInterceptor(client.internalCache()));

//ConnectInterceptor:负责和服务器建立连接
interceptors.add(new ConnectInterceptor(client));

//在配置OkHttpClient时设置的networkInterceptors
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}

//CallServerInterceptor:负责向服务器发送数据,从服务器读取响应数据
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);
}

其中,Interceptor(拦截器)是OkHttp中最核心的一个东西,它不仅负责拦截请求进行一些额外的处理,实际上它把网络请求、缓存、透明压缩等功能都统一了起来,每个功能都是一个Interceptor,它们连接成一个拦截链(Interceptor.Chain),一环接一环地完成一次网络请求,这种方式运用了责任链模式

拦截器的顺序如下:

  1. 用户在配置OkHttpClient时设置的interceptors
  2. RetryAndFollowUpInterceptor:负责失败重试和重定向
  3. BridgeInterceptor:负责把用户请求转换为发送到服务器的请求,并把服务器的响应转化为用户需要的响应
  4. CacheInterceptor:负责读取缓存、更新缓存
  5. ConnectInterceptor:负责和服务器建立连接
  6. 用户在配置OkHttpClient时设置的networkInterceptors
  7. CallServerInterceptor:负责向服务器发送数据,从服务器读取响应数据

在创建完拦截链后,会调用拦截链的proceed方法,接下来看RealInterceptorChain的proceed方法:

RealInterceptorChain#proceed

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
//...

//得到下一条拦截链,index + 1
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
//得到当前index对应的拦截器
Interceptor interceptor = interceptors.get(index);
//当前拦截器开始拦截,并得到Response
Response response = interceptor.intercept(next);

//...

return response;
}

该方法在等到当前拦截器和下一拦截链后,调用Interceptor的intercept方法。在各个Interceptor中,会完成自己所负责的功能,最后将结果传递给RealCall的execute方法,并通过该方法返回Response给用户。

各个拦截器具体干了什么请看这篇文章okhttp3源码分析:五大拦截器

异步请求

进行异步请求时,调用的是RealCall的enqueue方法:

RealCall#enqueue

1
2
3
4
5
6
7
8
9
10
11
12
13
 @Override 
public void enqueue(Callback responseCallback) {
synchronized (this) {
//判断该Call是否被执行,一个Call只能执行一次
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);

//调用Dispatcher的enqueue方法
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}

同样先判断该Call是否被执行,一个Call只能执行一次。之后调用Dispatcher的enqueue方法并传入AsyncCall:

1
2
3
4
5
6
7
8
9
10
11
 synchronized void enqueue(AsyncCall call) {
//如果异步请求队列中的请求数小于64,并且该Call对应的主机运行数小于5
//就把请求添加进异步请求队列并执行,否则添加到等待队列进行等待
if (runningAsyncCalls.size() < maxRequests
&& runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}

如果异步请求队列中的请求数小于64,并且该Call对应的主机运行数小于5就把请求添加进异步请求队列并在线程池中执行,否则添加到等待队列进行等待。

AsyncCall是一个Runnable,它的run方法会执行execute方法,AsyncCall的execute方法实现如下:

AsyncCall#execute

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
   @Override 
protected void execute() {
boolean signalledCallback = false;
try {
//执行拦截链并获得Response
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 {
//将此次的Request从异步请求队列中移除,然后从等待队列取出下一请求,加入异步请求队列并执行
client.dispatcher().finished(this);
}
}

可以看到,异步请求也是通过getResponseWithInterceptorChain执行拦截链并获得Response,只不过这次是在子线程中执行该方法。获得Response后,根据结果进行相应回调。最后将此次的Request从异步请求队列中移除,然后从等待队列还有请求的话就取出下一请求,加入异步请求队列并执行。

参考

-------------    本文到此结束  感谢您的阅读    -------------
0%