Okhttp源码分析
Okhttp在使用过程中我们表面能所看到的流程 大概是是这样,通过OkHttpClient将构建的Request转换为请求呼叫,然后在RealCall中进行异步或同步任务,最后通过一些的拦截器interceptor发出网络请求和得到返回的response
下面我们来看一张请求图。图片来自于网络作者,文末会注明。
我们先来一段 Okhttp 请求 事咧 (异步请求)
public void get(){
OkHttpClient mOkHttpClient = new OkHttpClient();
//建造者模式
final Request request = new Request.Builder()
.url("https://127.0.0.1:727/wms/getLocation")
.addHeader("tokenid","shiqi")
.build();
Call call = mOkHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if(response != null )
Log.i(TAG, "WMS:"+ String.valueOf(response.body().string()));
}
}
});
}
Request就不多说了 ,主要 存放 请求Url,params,Header 等等一系列参数请求头等
mOkHttpClient.newCall(request); 我们来看看这个newCall方法 进行了什么实质的操作
/**
* Prepares the {@code request} to be executed at some point in the future.
*/
@Override public Call newCall(Request request) {
return new RealCall(this, request, false /* for web socket */);
}
RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
final EventListener.Factory eventListenerFactory = client.eventListenerFactory();
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
// TODO(jwilson): this is unsafe publication and not threadsafe.
this.eventListener = eventListenerFactory.create(this);
}
通过源代码来看我们 得知 newCall方法 返回了 RealCall对象
什么是RealCall?他的作用是什么?Call是一个接口(呼叫是已准备好执行的请求) RealCall 是其真正的执行者 实现了Call 接口的方法
RealCall 是真正执行操作的请求者,呼叫对象,下面我们继续看 enqueue()方法
//异步任务使用
@Override
public void enqueue(Callback responseCallback) {
synchronized (this) {
//判断是否已经 请求过
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
//diapather 异步请求的策略
调度进行排队请求 client.dispatcher().enqueue(new AsyncCall(responseCallback));
synchronized void enqueue(AsyncCall call) {
//当前的请求数量 小于最大请求数量(并发量) 并且运行在客户端的数量 小于 机器的最大请求数量
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
//运行异步调用
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
//排队等待调用
readyAsyncCalls.add(call);
}
}
当前的请求数量 小于最大请求数量(并发量) 并且运行在客户端的数量 小于 机器的最大请求数量。就把当前排队的请求放到正在进行的异步请求队列中 , 否则就放到即将执行的队列中
我们先看看 这其中参数 ,参数位于Dispather类中
//当前最大请求数量 并发量 可以自己进行设置 该参数位于Dispather 类中
//mOkHttpClient.dispatcher().setMaxRequests(1000);
private int maxRequests = 64;
//客户端最大请求数量。可以修改
//mOkHttpClient.dispatcher().setMaxRequestsPerHost(100);
private int maxRequestsPerHost = 5;
private @Nullable Runnable idleCallback;
/** Executes calls. Created lazily. */
//请求的线程池
private @Nullable ExecutorService executorService;
/** Ready async calls in the order they'll be run. */
//将要运行的异步请求队列
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
/** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
//正在运行的 异步队列
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
/** Running synchronous calls. Includes canceled calls that haven't finished yet. */
//正在运行的同步队列
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
接下来我们看看 enqueue 方法中参数AsynCall call。onResponse ,onFailure 是不是有点熟悉 正是我们。在Call.enqueue 方法 的回调 结果处理 我们接着继续往下看
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);
}
}
}
executorService().execute(call);
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;
}
这个方法呢。主要 新新建一个线程池 , 线程池 最小核心数 0 ,最大线程数量为 Integer.MAX_VALUE ,空闲线程时间为60秒 ,我们创建完线程池。是时候开始 做请求操作了。
我们回到 上面讲的AnsyCall 方法中我们仔细来看看 是如何进行操作的 在execute方法中 的getResponseWithInterceptorChain()方法来获取 服务端 返回的Response 结果 进行判断 请求成功与否如果请求被取消则在进行OnFailue回调,如果请求成功则进行onResponse的回调。
这里要注意两点:
- 请求如果被取消,其回调实在onFailue中进行回调的
- 排队方法的回调是在子线程中完成的
下面我们看看 getResponseWithInterceptorChain()方法 为什么 他能够 获取到。服务端 的数据 。他进行了什么操作
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
//责任链 集合
List<Interceptor> interceptors = new ArrayList<>();
//拦截器
interceptors.addAll(client.interceptors());
// 链式重链 30秒内无响应重新请求。(举例)
interceptors.add(retryAndFollowUpInterceptor);
//用户请求参数转化 再将服务器响应的数据转换为 BridgeInterceptor
//负责把用户构造的请求转换为发送到服务器的请求 、把服务器返回的响应转换为用户友好的响应 处理 配置请求头等 信息
interceptors.add(new BridgeInterceptor(client.cookieJar()));
//更新缓存
interceptors.add(new CacheInterceptor(client.internalCache()));
//负责 和 服务器建立连接
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
//配置Okhttp networkInterceptors
interceptors.addAll(client.networkInterceptors());
}
//发送请求。读取响应数据
interceptors.add(new CallServerInterceptor(forWebSocket));
//链式调用
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}
我们来看看链式调用
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0, originalRequest);
这个方法 是将上面的 我们定义的 interceotors拦截器结合 ,originalRequest -> 也就是我们写的Request
RealInterceptorChain
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
calls++;
// If we already have a stream, confirm that the incoming request will use it.
//如果我们已经有一个stream。确定即将到来的request会使用它
if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must retain the same host and port");
}
// If we already have a stream, confirm that this is the only call to chain.proceed().
//如果我们已经有一个stream, 确定chain.proceed()唯一的call
if (this.httpCodec != null && calls > 1) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must call proceed() exactly once");
}
// Call the next interceptor in the chain.\
//调用链的下一个拦截器
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpCodec, connection, index + 1, request);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
// Confirm that the next interceptor made its required call to chain.proceed().
//确认下一个拦截器对chain.process()进行了所需的调用。
if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
throw new IllegalStateException("network interceptor " + interceptor
+ " must call proceed() exactly once");
}
// Confirm that the intercepted response isn't null.
//确认截获的响应不为空
if (response == null) {
throw new NullPointerException("interceptor " + interceptor + " returned null");
}
return response;
}
上段代码中午 重要部分
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpCodec, connection, index + 1, request);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
1.interceptors 我们在getResponseWithInterceptorChain 添加的责任链 (拦截器)集合 进行循环调用
第一个添加的就是—》RetryAndFollowUpInterceptor:负责失败重试以及重定向
代码比较长 贴部分代码
Response response = null;
boolean releaseConnection = true;
try {
response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, null, null); //(1)
releaseConnection = false;
} catch (RouteException e) {
// The attempt to connect via a route failed. The request will not have been sent.
//通过路线连接失败,请求将不会再发送
if (!recover(e.getLastConnectException(), true, request)) throw e.getLastConnectException();
releaseConnection = false;
continue;
} catch (IOException e) {
// An attempt to communicate with a server failed. The request may have been sent.
// 与服务器尝试通信失败,请求不会再发送。
if (!recover(e, false, request)) throw e;
releaseConnection = false;
continue;
} finally {
// We're throwing an unchecked exception. Release any resources.
//抛出未检查的异常,释放资源
if (releaseConnection) {
streamAllocation.streamFailed(null);
streamAllocation.release();
}
}
// Attach the prior response if it exists. Such responses never have a body.
// 附加上先前存在的response。这样的response从来没有body
// TODO: 2016/8/23 这里没赋值,岂不是一直为空?
if (priorResponse != null) { // (2)
response = response.newBuilder()
.priorResponse(priorResponse.newBuilder()
.body(null)
.build())
.build();
}
在上述代码中 主要还是 第一步调用下一个拦截器 并且对当前的请求做对应的异常处理
response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, null, null);
2 .BridgeInterceptor 负责把用户构造的请求转换为发送到服务器的请求、把服务器返回的响应转换为用户友好的响应的
@Override
public Response intercept(Chain chain) throws IOException {
Request userRequest = chain.request();
Request.Builder requestBuilder = userRequest.newBuilder();
//检查request。将用户的request转换为发送到server的请求
RequestBody body = userRequest.body(); //(1)
if (body != null) {
MediaType contentType = body.contentType();
if (contentType != null) {
requestBuilder.header("Content-Type", contentType.toString());
}
long contentLength = body.contentLength();
if (contentLength != -1) {
requestBuilder.header("Content-Length", Long.toString(contentLength));
requestBuilder.removeHeader("Transfer-Encoding");
} else {
requestBuilder.header("Transfer-Encoding", "chunked");
requestBuilder.removeHeader("Content-Length");
}
}
if (userRequest.header("Host") == null) {
requestBuilder.header("Host", hostHeader(userRequest.url(), false));
}
if (userRequest.header("Connection") == null) {
requestBuilder.header("Connection", "Keep-Alive");
}
// If we add an "Accept-Encoding: gzip" header field we're responsible for also decompressing
// the transfer stream.
//GZIP压缩
boolean transparentGzip = false;
if (userRequest.header("Accept-Encoding") == null) {
transparentGzip = true;
requestBuilder.header("Accept-Encoding", "gzip");
}
List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
if (!cookies.isEmpty()) {
requestBuilder.header("Cookie", cookieHeader(cookies));
}
if (userRequest.header("User-Agent") == null) {
requestBuilder.header("User-Agent", Version.userAgent());
}
Response networkResponse = chain.proceed(requestBuilder.build()); //(2)
HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers()); //(3)
Response.Builder responseBuilder = networkResponse.newBuilder()
.request(userRequest);
if (transparentGzip
&& "gzip".equalsIgnoreCase(networkResponse.header("Content-Encoding"))
&& HttpHeaders.hasBody(networkResponse)) {
GzipSource responseBody = new GzipSource(networkResponse.body().source());
Headers strippedHeaders = networkResponse.headers().newBuilder()
.removeAll("Content-Encoding")
.removeAll("Content-Length")
.build();
responseBuilder.headers(strippedHeaders);
responseBuilder.body(new RealResponseBody(strippedHeaders, Okio.buffer(responseBody)));
}
return responseBuilder
}
1)先对于
request的格式进行检查
2)调用下一个interceptor
来得到response
3)下面就是对得到的response进行一些判断操作,最后将结果返回。
3.CacheInterceptor 再下来就是缓存的使用
4.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, doExtensiveHealthChecks);
RealConnection connection = streamAllocation.connection();
return realChain.proceed(request, streamAllocation, httpCodec, connection);
}
在上述建立连接的代码中主要是 创建的了HttpCodec对象 他是对http 协议操作的的抽象
5.配置OkHttpClient时设置的 NetworkInterceptors。
6.CallServerInterceptor:发送和接收数据
@Override public Response intercept(Chain chain) throws IOException {
HttpCodec httpCodec = ((RealInterceptorChain) chain).httpStream();
StreamAllocation streamAllocation = ((RealInterceptorChain) chain).streamAllocation();
Request request = chain.request();
long sentRequestMillis = System.currentTimeMillis();
httpCodec.writeRequestHeaders(request);
if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) { //===(1)
Sink requestBodyOut = httpCodec.createRequestBody(request, request.body().contentLength());
BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
request.body().writeTo(bufferedRequestBody);
bufferedRequestBody.close();
}
httpCodec.finishRequest();
Response response = httpCodec.readResponseHeaders() //====(2)
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
if (!forWebSocket || response.code() != 101) {
response = response.newBuilder()
.body(httpCodec.openResponseBody(response))
.build();
}
if ("close".equalsIgnoreCase(response.request().header("Connection"))
|| "close".equalsIgnoreCase(response.header("Connection"))) {
streamAllocation.noNewStreams();
}
int code = response.code();
if ((code == 204 || code == 205) && response.body().contentLength() > 0) {
throw new ProtocolException(
"HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());
}
return response;
}
HttpCodec 开始处理 request 得到responese 在反回到客户端
3.同步请求
//HTTP GET
public String get(String url) throws IOException {
//新建OKHttpClient客户端
OkHttpClient client = new OkHttpClient();
//新建一个Request对象
Request request = new Request.Builder()
.url(url)
.build();
//Response为OKHttp中的响应
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
return response.body().string();
}else{
throw new IOException("Unexpected code " + response);
}
}
同步内容和异常 基本一致主要在于 execute方法 同步无需 new CallBack, execute直接返回了 Respnse结果
其余大体一致
@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);
}
}
本文参考修改来源于 [mecury](https://www.jianshu.com/u/dd2aad4c6950 兄弟。 感谢?
本文记录 学习笔记