Retrofit,OkHttp,Okio Square 安卓平台网络层三板斧源码学习
基于 okhttp 3.9.0 版本 okhttp github 地址
使用方式
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
- 构造一个 Request
- 调用 OkHttpClient.newCall(Request request) 获得一个 Call 对象
- 执行 Call.execute() 获得 Response 对象
- 通过 Response.body() 获得 ResponseBody 对象
OkHttpClient 创建 http 请求源码分析。
OkHttpClient 和 OkHttpClient.Builder
OkHttpClient 对象的创建使用了『建造者模式』
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;
}
OkHttpClient.Builder 主要用来设置超时时间、代理、缓存、拦截器等。
然后调用
public OkHttpClient build() {
return new OkHttpClient(this);
}
创建 OkHttpClient
OkHttpClient(Builder builder) {
this.dispatcher = builder.dispatcher;
this.proxy = builder.proxy;
this.protocols = builder.protocols;
this.connectionSpecs = builder.connectionSpecs;
this.interceptors = Util.immutableList(builder.interceptors);
this.networkInterceptors = Util.immutableList(builder.networkInterceptors);
this.eventListenerFactory = builder.eventListenerFactory;
……
}
Request 和 Request.Builder
Request 同样也是使用『建造者模式』
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;
}
Request 主要为了设置 url 、请求方法(GET、POST等)、headers、请求体。
其中有个 tag 比较特殊
/**
* Attaches {@code tag} to the request. It can be used later to cancel the request. If the tag
* is unspecified or null, the request is canceled by using the request itself as the tag.
*/
public Builder tag(Object tag) {
this.tag = tag;
return this;
}
根据注释可以看出 tag 主要用来取消请求。
如果发起 POST 请求,需要使用一个 RequestBody
okhttp_01.pngRequestBody 主要用来设置不同的 POST 请求内容(字节流、文件、字符串)
分析 Call 对象
client.newCall(request)
OkHttpClient 的 newCall
@Override
public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
发现请求代理给了 RealCall
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
// Safely publish the Call instance to the EventListener.
RealCall call = new RealCall(client, originalRequest, forWebSocket);
call.eventListener = client.eventListenerFactory().create(call);
return call;
}
看下 RealCall 的构造函数
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
}
获得 Call.execute() 和 Call.enqueue(Callback responseCallback)
Call.execute() 负责同步请求。
Call.enqueue(Callback responseCallback) 负责异步请求。
@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));
}
从上面代码可以看出 Call 对象会交给 Dispatcher 对象进行管理。
executed() 方法会把 Call 对象存放在 runningSyncCalls 队列
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
enqueue() 方法会把 Call 对象存放在 runningAsyncCalls 队列,如果队列已满则会被存放在 readyAsyncCalls 队列
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
然后会执行到 getResponseWithInterceptorChain
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, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
return chain.proceed(originalRequest);
}
这里可以看到添加了一些列的 Interceptor 对象。这些 intercept 分别负责网络请求、缓存、压缩等功能。
而这些 intercept 组合的方式就是『责任链模式』,而最后一个 CallServerInterceptor 会真正发起网络请求。
1. 首先会创建一个 RealInterceptorChain ,传入所有的 Interceptor,index = 0
2. 然后执行 RealInterceptorChain.proceed(Request request)
3. 再调用 RealInterceptorChain.proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection)
4. 创建一个新的 RealInterceptorChain ,传入 index 值 +1,对象名称为 next
5. 获取 interceptors 中 index 位置的 Interceptor,调用 Interceptor.intercept(next)
6. 在 interceptors 中添加的各种 Interceptor 的 intercept 中都会如下
public Response intercept(Chain chain) throws IOException {
……
chain.proceed(requestBuilder.build());
// or
realChain.proceed(request, streamAllocation, null, null);
……
}
7. 其中 Chain.proceed() 方法又会重复执行 3、4、5、6 步骤,直到所有的 interceptors 被遍历。
8. 最后添加的 ConnectInterceptor 和 CallServerInterceptor 是发起网络请求的关键
总结以上流程如下
okhttp_02.png发起网络请求
先看 ConnectInterceptor
@Override
public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Request request = realChain.request();
StreamAllocation streamAllocation = realChain.streamAllocation();
// We need the network to satisfy this request. Possibly for validating a conditional GET.
boolean doExtensiveHealthChecks = !request.method().equals("GET");
HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
RealConnection connection = streamAllocation.connection();
return realChain.proceed(request, streamAllocation, httpCodec, connection);
}
其中 StreamAllocation 对象由 RetryAndFollowUpInterceptor 创建并传入到『责任链』中。
public Response intercept(Chain chain) throws IOException {
……
streamAllocation = new StreamAllocation(client.connectionPool(), createAddress(request.url()),
call, eventListener, callStackTrace);
……
response = realChain.proceed(request, streamAllocation, null, null);
……
}
}
可以看出 ConnectInterceptor 主要作用就是通过 StreamAllocation 创建了一个 HttpCodec。
public HttpCodec newStream(
OkHttpClient client, Interceptor.Chain chain, boolean doExtensiveHealthChecks) {
int connectTimeout = chain.connectTimeoutMillis();
int readTimeout = chain.readTimeoutMillis();
int writeTimeout = chain.writeTimeoutMillis();
boolean connectionRetryEnabled = client.retryOnConnectionFailure();
try {
RealConnection existingConnection = connection;
RealConnection resultConnection = findHealthyConnection(connectTimeout, readTimeout,
writeTimeout, connectionRetryEnabled, doExtensiveHealthChecks);
HttpCodec resultCodec = resultConnection.newCodec(client, chain, this);
if (existingConnection != connection) {
eventListener.connectionAcquired(call, connection);
}
synchronized (connectionPool) {
codec = resultCodec;
return resultCodec;
}
} catch (IOException e) {
throw new RouteException(e);
}
}
通过上面代码我们可以看出虽然返回的只是一个 HttpCodec 但是还会创建一个 RealConnection 。而 RealConnection 则是负责连接服务器发送请求的类。
findHealthyConnection() 方法会调用 findConnection() 方法
private RealConnection findConnection(int connectTimeout, int readTimeout, int writeTimeout,
boolean connectionRetryEnabled) throws IOException {
……
RealConnection result;
……
// Do TCP + TLS handshakes. This is a blocking operation.
result.connect(
connectTimeout, readTimeout, writeTimeout, connectionRetryEnabled, call, eventListener);
……
}
并且调用 RealConnection 的 connect() 方法进行连接
public void connect(int connectTimeout, int readTimeout, int writeTimeout,
boolean connectionRetryEnabled, Call call, EventListener eventListener) {
……
connectSocket(connectTimeout, readTimeout, call, eventListener);
……
}
private void connectSocket(int connectTimeout, int readTimeout, Call call,
EventListener eventListener) throws IOException {
Proxy proxy = route.proxy();
Address address = route.address();
rawSocket = proxy.type() == Proxy.Type.DIRECT || proxy.type() == Proxy.Type.HTTP
? address.socketFactory().createSocket()
: new Socket(proxy);
eventListener.connectStart(call, route.socketAddress(), proxy);
rawSocket.setSoTimeout(readTimeout);
try {
Platform.get().connectSocket(rawSocket, route.socketAddress(), connectTimeout);
}
……
try {
source = Okio.buffer(Okio.source(rawSocket));
sink = Okio.buffer(Okio.sink(rawSocket));
} ……
}
这里可以看出 connect() 方法会简历一个 Socket 连接,并把 Socket 的输入/输出流交包装成 Okio 的 Source 和 Sink 对象。
然后到 CallServerInterceptor 中
public Response intercept(Chain chain) throws IOException {
……
Response.Builder responseBuilder = null;
if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
……
//写入 request body
……
}
httpCodec.finishRequest(); // 通过 Socket OutputStream 发送请求
……
if (responseBuilder == null) {
realChain.eventListener().responseHeadersStart(realChain.call());
responseBuilder = httpCodec.readResponseHeaders(false);
}
Response response = responseBuilder
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
……
return response;
}
总计流程图如下
okhttp_03.png okhttp_04.png
网友评论