OkHttp简析

OkHttp流程图

OkHttp流程图

基础用法

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
//1.
OkHttpClient okHttpClient = new OkHttpClient()
.newBuilder()
.connectTimeout(60, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.addInterceptor(new LogInterceptor())
.build();

//2.
final Request request = new Request.Builder()
.url("http://wanandroid.com/wxarticle/chapters/json")
.build();
//3.
Call call = okHttpClient.newCall(request);

//4.1执行同步请求
Response response = okHttpClient.newCall(request).execute();
System.out.println(response.body().string());

//4.2执行异步请求
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {

}

@Override
public void onResponse(Call call, Response response) throws IOException {
System.out.println(response.body().string());
}
});

所以OkHttp同步/异步请求的步骤就是:

  1. 创建一个OkHttpClient,并添加一些配置。详细的写在下面
  2. 构建一个Request
  3. 使用OkHttp和Request构建一个Call
  4. 执行同步/异步请求,得到Response

OkHttpClient

作用:

  1. 配置参数:采用了 构建者模式 ,在new Build()中为其设置了许多的默认参数。
  2. 实现了Call.Factory接口,重写newCall方法,返回一个RealCall对象
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
public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {

final Dispatcher dispatcher; //分发器
final @Nullable Proxy proxy; //代理
final List<Protocol> protocols; //协议
final List<ConnectionSpec> connectionSpecs;
final List<Interceptor> interceptors; //拦截器
final List<Interceptor> networkInterceptors; //网络拦截器
final EventListener.Factory eventListenerFactory; //
final ProxySelector proxySelector; //代理选择
final CookieJar cookieJar; //Cookie
final @Nullable Cache cache; //缓存
final @Nullable InternalCache internalCache; //内部缓存
final SocketFactory socketFactory; //socket工厂
final @Nullable SSLSocketFactory sslSocketFactory; //sslSocket工厂
final @Nullable CertificateChainCleaner certificateChainCleaner;//验证确认
final HostnameVerifier hostnameVerifier; //主机名字确认
final CertificatePinner certificatePinner;
final Authenticator proxyAuthenticator; //代理身份验证
final Authenticator authenticator; //本地身份验证
final ConnectionPool connectionPool; //连接处
final Dns dns; //dns
final boolean followSslRedirects; //。。
final boolean followRedirects; //。。
final boolean retryOnConnectionFailure; //连接失败重试
final int connectTimeout; //连接超时
final int readTimeout; //read超时
final int writeTimeout; //write超时
final int pingInterval; //

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

public static final class Builder {
//省略n个属性
public Builder() {
//省略属性设置代码
}
Builder(OkHttpClient okHttpClient) {
//省略属性设置代码
}
public OkHttpClient build() {
return new OkHttpClient(this);
}
}
}

Request

Request是请求,包括:

  • url
  • method :请求方法
  • headers: 请求头
  • RequestBody:RequestBody是abstract的,包含两个子类FormBody和MultipartBody。
    • FormBody:表单提交。MIME类型为 :”application/x-www-form-urlencoded”
      MultipartBody:”multipart/“+xxx.
    • MultipartBody:文件上传。MIME类型为:”multipart/“+xxx.“

Call

Call是个接口类,是Http请求任务封装。

设计模式:工厂方法模式,将对象的创建延迟到工厂类的子类进行,实现了动态配置。

提供了内部接口Factory。

实现类有RealCall和CacheCall。

RealCall

RealCall是Call的实现类,是请求中真正调用的Call。

构造方法中包装了OkHttpClienthe和Request对象。并且有三个重要的方法:

  • execute() :执行同步请求
  • enqueue():执行异步请求
  • getResponseWithInterceptorChain ():添加拦截器,并获取最终的Response

RealCall#execute()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Override
public Response execute() throws IOException {
synchronized (this) {
//1
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
//2
captureCallStackTrace();
try {
//3
client.dispatcher.executed(this);
//4
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
}finally {
//5
client.dispatcher.finished(this);
}
}
  1. 判断call是否已经执行过,表示每个Call对象只能使用一次
  2. 捕获了这个请求的StackTrace。(可以跳过不看)
  3. 调用Dispatcher#executed( )方法,将请求添加到runningSyncCalls(存放同步请求的队列)中
  4. 调用getResponseWithInterceptorChain()获取Response,里面包含了一系列的拦截
  5. 通知Dispatcher执行结束

其中getResponseWithInterceptor是重点,后面会进行分析

RealCall#enqueue()

1
2
3
4
5
6
7
8
@Override 
public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}

实际上是调用了Dispatcher#enqueue()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Dispatcher.class

synchronized void enqueue(AsyncCall call) {
//1
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
//2
runningAsyncCalls.add(call);
//3
executorService().execute(call);
} else {
//4
readyAsyncCalls.add(call);
}
}
  1. 判断正在执行的请求小于设定值(64),并且请求同一个主机的request小于设定值(5)
  2. 添加到runningAsyncCalls(执行队列),开始执行请求
  3. 获得当前线程池,没有则创建一个,并excute()(重点)
  4. 假如不是1的情况,将请求添加到readyAsyncCall(s等待队列)中

在3中,实际上调用的是AsyncCall的run( )方法,AsyncCall继承自NamedRunnable。看看NamedRunnable#run()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public abstract class NamedRunnable implements Runnable {

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

NamedRunnable#run()方法中设置了线程的name,然后回调子类的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
28
29
30
//AsyncCall.class

@Override
protected void execute() {
boolean signalledCallback = false;
try {
//1
Response response = getResponseWithInterceptorChain();
if (retryAndFollowUpInterceptor.isCanceled()) {
//2
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
//3
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
}
} catch (IOException e) {
//4
if (signalledCallback) {
// Do not signal the callback twice!
Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
} else {
responseCallback.onFailure(RealCall.this, e);
}
} finally {
//5
client.dispatcher().finished(this);
}
}
  1. 执行getResponseWithInterceptorChain()
  2. 失败回调
  3. 成功回调
  4. 失败回调
  5. 通知Dispatcher请求结束

所以重点又是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
//RealCall.class

Response getResponseWithInterceptorChain() throws IOException {
// 1
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));

//2
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());

//3
return chain.proceed(originalRequest);
}
  1. 创建一个拦截器列表interceptors,并且添加各种拦截器
  2. 创建RealInterceptorChain
  3. 把chain传递到第一个Interceptor手中

分析一下RealInterceptorChain的proceed()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
...
//省略一系列的判断代码。。。
...
//1
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
//2
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
return response;
}
  1. ,构建下一个索引值为index+1的RealInterceptorChain对象next。next和该chain对象最大的区别就是索引值从index 变成index+1了,也就是拦截器列表中interceptors的下一个拦截器interceptor。
  2. 获取拦截器列表索引为index的interceptor,并执行其intercept()方法

回到RealCall#getResponseWithInterceptorChain()中,interceptors先添加的是自定义的拦截器client.interceptors(),然后是RetryAndFollowUpInterceptor、 BridgeInterceptor、 CacheInterceptor、ConnectInterceptor、NetworkInterceptor、CallServerInterceptor。

因此getResponseWithInterceptorChain()会递归调用所有拦截器的intercept()方法,最终调用的是CallServerInterceptor的intercept()直接返回了Response,不在进行递归调用。

Response

Response是响应,包括

  • Request:
  • code:
  • headers: 响应头
  • ResponseBody:ResponseBody也是abstract的,包含两个子类FormBody和MultipartBody。
    • RealResponseBody:真实响应
    • CacheResponseBody:缓存响应

结语

OkHttp目前能看懂的大概就是这些了,其他一些协议,socket相关的内容因为水平原因,就不进行分析啦。

设计模式:采用了建造者模式,工厂方法模式,责任链模式等等设计模式。

贴一下思维导图,希望大家有空仔细看看RealCall#getResponseWithInterceptorChain( )方法和各个拦截器的intercept()方法

OkHttp思维导图

参考

Android OkHttp完全解析 是时候来了解OkHttp了

拆轮子系列:拆OkHttp

OKHttp源码解析(一)–初阶