OkHttp源码结构分析

基本概念

之前一篇简单介绍了OkHttp的概况和使用方式,以及如何与Volley一起使用,知其然也要知其所以然,这一篇大概介绍下这个网络框架的源码结构。基于OkHttp 3.5.0

基本流程

OkHttp源码结构图

这个框架作为Android开发者应该是很熟悉的。入口的构建是建造者模式,在请求的时候手动构建一个Request,通过OkHttpClientnewCall()方法发起请求,获取Response,也就是请求最终的结果。代码如下:

1
2
3
4
5
6
7
8
9
10
11

OkHttpClient client = new OkHttpClient();

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

Response response = client.newCall(request).execute();
return response.body().string();
}

主要组件

OkHttpClient.Bulider

  • 负责构建OkHttpClient,Square官方的建议是全局共用一个OkHttpClient,实际上OkHttpClient虽然有public的狗仔方法,内部也是传入一个默认的Builder.

OkHttpClient

  • 处理配置这个client的参数,核心方法其实就一个:
1
2
3
4

@Override public Call newCall(Request request) {
return new RealCall(this, request, false);
}

Request

  • 这个类只用来存储请求的数据,不做实际的事情,具体请求的发起由下一个RealCall来做

RealCall

  • RealCall实现了Call接口,关于这个接口的作用,注释已经说清楚了,RealCall是唯一的实现,也就是OkHttp实际用来请求的类

A call is a request that has been prepared for execution. A call can be canceled. As this object
represents a single request/response pair (stream), it cannot be executed twice.

  • 那么怎么干活呢?Call这个接口有两个关键的实现方法,execute()enqueue(),方法名意思已经很明确了,一个同步一个异步,我们只需要看这两个方法的实现就可以了:
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

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

@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}

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,异步方法则间接一点,包装一个Runnable扔给线程池,本质上最终使用的也是getResponseWithInterceptorChain()。然后我们就要看这个方法是何方神圣了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

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);
return chain.proceed(originalRequest);
}

熟悉OkHttp的同学都知道OkHttp有一个很厉害的东西,叫Interceptor,只要实现了这个接口,就可以在一个请求的RequestResponse之间做很多文章,比如写个LogInterceptor打印请求的各种信息,实现也特别优雅,但是看了源码才知道,Interceptor贯穿了请求的全部,无论是重试机制、缓存还是具体请求,实际上都是通过Interceptor来做的。那么接下来就分析源码中用到的这些Interceptor.

RetryAndFollowUpInterceptor

  • 负责重试和重定向

BridgeInterceptor

  • 负责把请求转换为发送给服务器的请求,把服务器返回的结果包装成我们接收到的Response

CacheInterceptor

  • 缓存命中时则直接返回结果,未命中时则在网络请求结果返回时更新缓存

ConnectInterceptor

  • 负责与服务器建立连接

CallServerInterceptor

  • 负责向服务器发送请求,从服务器读取返回结果

环环相扣,是一个典型的责任链模式,这些Interceptor与我们平时写的简单的Interceptor本质是一样的,都是实现一个intercept(Chain chain)方法,然后在RequestResponse上做文章,但是套在一起,就实现了一个完整的网络请求过程,同时还完成了重试、缓存这些工作。具体的代码就不分析了···因为具体发起请求和读取返回结果又是HttpCodecOkio这两个大家伙的工作,分析起来又是大把的时间耗在里面了(都是泪)。有兴趣的同学可以读读看。如果只是分析OkHttp大的源码结构的话,这几个类就足够了。