说到StreamAllocation的解读,需要先看多上一篇章对okHttp3框架的解读:
这篇主要分析StreamAllocation的源码:
public StreamAllocation(ConnectionPool connectionPool, Address address, Call call,
EventListener eventListener, Object callStackTrace) {
this.connectionPool = connectionPool;//连接池管理
this.address = address;
this.call = call;//realCall
this.eventListener = eventListener;
this.routeSelector = new RouteSelector(address, routeDatabase(), call, eventListener);//routeDatabase()(ConnectionPool类的routeDatabase常量), 该对象为处理连接到原服务器的路由
this.callStackTrace = callStackTrace;
}
构造函数中,初始化了一个连接到原服务器的路由地址管理工具;这里展开讲解下RouteSelector:
public RouteSelector(Address address, RouteDatabase routeDatabase, Call call,
EventListener eventListener) {
this.address = address;
this.routeDatabase = routeDatabase;
this.call = call;
this.eventListener = eventListener;
resetNextProxy(address.url(), address.proxy());
}
关键方法resetNextProxy:
private void resetNextProxy(HttpUrl url, Proxy proxy) {
if (proxy != null) {
// If the user specifies a proxy, try that and only that.
proxies = Collections.singletonList(proxy);//如果okhttp配置的代理不为空的话,直接使用ok配置的代理
} else {
// Try each of the ProxySelector choices until one connection succeeds.
List<Proxy> proxiesOrNull = address.proxySelector().select(url.uri());//尝试系统的代理选择器
proxies = proxiesOrNull != null && !proxiesOrNull.isEmpty()
? Util.immutableList(proxiesOrNull)
: Util.immutableList(Proxy.NO_PROXY);//直连,不使用代理
}
nextProxyIndex = 0;//代理获取计数器
}
接下来,看看StreamAllocation的newStream方法,这个方法在拦截器ConnectInterceptor中调用,用来打开连接:
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 resultConnection = findHealthyConnection(connectTimeout, readTimeout,
writeTimeout, connectionRetryEnabled, doExtensiveHealthChecks);//打开连接
HttpCodec resultCodec = resultConnection.newCodec(client, chain, this);//获取http协议版本解析器
synchronized (connectionPool) {
codec = resultCodec;
return resultCodec;
}
} catch (IOException e) {
throw new RouteException(e);
}
}
这里我们看看HttpCodec是做什么的:
public interface HttpCodec {
/**
* The timeout to use while discarding a stream of input data. Since this is used for connection
* reuse, this timeout should be significantly less than the time it takes to establish a new
* connection.
*/
int DISCARD_STREAM_TIMEOUT_MILLIS = 100;
/** Returns an output stream where the request body can be streamed. */
Sink createRequestBody(Request request, long contentLength);
/** This should update the HTTP engine's sentRequestMillis field. */
void writeRequestHeaders(Request request) throws IOException;
/** Flush the request to the underlying socket. */
void flushRequest() throws IOException;
/** Flush the request to the underlying socket and signal no more bytes will be transmitted. */
void finishRequest() throws IOException;
/**
* Parses bytes of a response header from an HTTP transport.
*
* @param expectContinue true to return null if this is an intermediate response with a "100"
* response code. Otherwise this method never returns null.
*/
Response.Builder readResponseHeaders(boolean expectContinue) throws IOException;//读取响应头部
/** Returns a stream that reads the response body. */
ResponseBody openResponseBody(Response response) throws IOException;//返回读取响应体的流
/**
* Cancel this stream. Resources held by this stream will be cleaned up, though not synchronously.
* That may happen later by the connection pool thread.
*/
void cancel();//取消流,非同步,
}
可以看到httpCodec的继承类,都是实现了请求、响应头部的写入与读取,以及创建请求、响应实体的流;
具体实现类在http1Codec、http2Codec包中,这里不做进一步解析;
至此StreamAllocation类就分析完毕了