简单使用流程
1、创建Requset对象
val URL : String = "http://www.baidu.com"
val request: Request = Request.Builder()
.url(URL)
.get()
.build()
2、创建OkHttp对象
val okHttpClient = OkHttpClient.Builder().build()
3、创建Call对象
通过前面创建的request和okhttp创建Call对象
val call: Call = okHttpClient.newCall(request)
4、请求网络,分为两种,同步请求和异步请求。
(1)同步请求:
Thread(object : Runnable {
override fun run() {
val response: Response = call.execute()
Log.d(TAG, "onResponse: " + response.body()!!.string());
}
}).start();
调用execute()方法,会阻塞当前线程。因为现在Android高版本不允许在主线程请求网络,所以其实也是在子线程中请求的网络。
(2)异步请求:
call.enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
Log.d(TAG, "onFailure: ");
}
override fun onResponse(cal: Call, response: Response){
Log.d(TAG, "onResponse: " + response.body()!!.string());
}
});
调用enqueue()方法,结果通过回调返回。
源码分析
以异步请求为例子,看一下源码是怎么实现的。
先来看Request的创建过程。
val request: Request = Request.Builder()
.url(URL)
.get()
.build()
使用工厂方法创建
public Builder() {
this.method = "GET";
this.headers = new Headers.Builder();
}
发现在Build()中,this.method默认返回了GET,说明如果不进行设置,默认这是一个Get请求。
接下来设置一些参数,比如通过url()设置http或https地址,get()表明这是一个get请求,也可以设置post()等,最后调用build()返回创建的Request对象。
public Request build() {
if (url == null) throw new IllegalStateException("url == null");
return new Request(this);
}
接下来创建OkHttpClient对象,也可以通过Build().build()的工厂方法模式创建,不具体写了。
val okHttpClient = OkHttpClient.Builder().build()
接着创建call
val call: Call = okHttpClient.newCall(request)
进到newCall()方法中。
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
调用了RealCall类的newRealCall()方法。
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类型的对象。ReallCal其实是一个Call的实现类。
final class RealCall implements Call {
...
}
接着就是请求网络了,这里分析的是异步请求enqueue()。
call.enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
Log.d(TAG, "onFailure: ");
}
override fun onResponse(cal: Call, response: Response){
Log.d(TAG, "onResponse: " + response.body()!!.string());
}
});
进到RealCall的enqueue方法
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
client.dispatcher()返回了前面创建的Dispatcher对象。先来看一下enqueue()方法中的参数,创建了一个AsyncCall类型的对象。
final class AsyncCall extends NamedRunnable {
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
}
AsyncCall继承自NamedRunnable,而NamedRunnable继承自Runnable。
回到enqueue方法中,进到Dispatcher的enqueue()方法中。
void enqueue(AsyncCall call) {
synchronized (this) {
readyAsyncCalls.add(call);
}
promoteAndExecute();
}
首先将Callback加入到未执行队列中,然后调用了promoteAndExecute()方法。
private boolean promoteAndExecute() {
assert (!Thread.holdsLock(this));
List<AsyncCall> executableCalls = new ArrayList<>();
boolean isRunning;
synchronized (this) {
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall asyncCall = i.next();
if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
if (runningCallsForHost(asyncCall) >= maxRequestsPerHost) continue; // Host max capacity.
i.remove();
executableCalls.add(asyncCall);
runningAsyncCalls.add(asyncCall);
}
isRunning = runningCallsCount() > 0;
}
for (int i = 0, size = executableCalls.size(); i < size; i++) {
AsyncCall asyncCall = executableCalls.get(i);
asyncCall.executeOn(executorService());
}
return isRunning;
}
首先创建一个局部变量的队列executableCalls,通过for循环去遍历readyAsyncCalls也就是未执行任务列表。当正在执行的任务数未达到设定的最大值maxRequests并且相同host下最多运行的请求数未达到最大值maxRequestsPerHost的话,将当前遍历到的任务从未执行队列readyAsyncCalls中移除,并将其加入到执行队列runningAsyncCalls和局部变量队列executableCalls中。再次通过一个for循环取出任务,调用executeOn()方法。先来看一下executorService()。
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;
}
创建了一个线程池。接着进到AsyncCall的executeOn()方法中
void executeOn(ExecutorService executorService) {
assert (!Thread.holdsLock(client.dispatcher()));
boolean success = false;
try {
executorService.execute(this);
success = true;
} catch (RejectedExecutionException e) {
InterruptedIOException ioException = new InterruptedIOException("executor rejected");
ioException.initCause(e);
eventListener.callFailed(RealCall.this, ioException);
responseCallback.onFailure(RealCall.this, ioException);
} finally {
if (!success) {
client.dispatcher().finished(this); // This call is no longer running!
}
}
}
在try块中调用了线程池的execute方法。这个时候应该会执行对应线程的run()方法,但具体执行的是哪个线程呢。前面看到过AsyncCall继承自NamedRunnable。进到NamedRunnable类中,发现了run()方法。
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();
在run()中调用了execute()方法,这是NamedRunnable类的一个抽象方法,具体的实现由子类完成,就是AsyncCall()类,也就是executorService.execute(this)中的this。这其实是一个模板方法模式。
进到子类AsyncCall中的execute()方法。
@Override protected void execute() {
boolean signalledCallback = false;
timeout.enter();
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) {
e = timeoutExit(e);
if (signalledCallback) {
// Do not signal the callback twice!
Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
} else {
eventListener.callFailed(RealCall.this, e);
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
这是一个try-catch-finally块,无论是否抛出异常,都会执行finally中的代码。在finally中调用了Dispatch的finished()方法。
void finished(AsyncCall call) {
finished(runningAsyncCalls, call);
}
继续调用finished()方法。
private <T> void finished(Deque<T> calls, T call) {
Runnable idleCallback;
synchronized (this) {
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
idleCallback = this.idleCallback;
}
boolean isRunning = promoteAndExecute();
if (!isRunning && idleCallback != null) {
idleCallback.run();
}
}
又调用了promoteAndExecute()方法,如果还有未执行的任务的话,会继续重复上面的步骤执行下一个任务。所以异步调用中,一个请求的阻塞不会影响到其他的请求。
回到上面的execute()方法,继续看真正开始请求网络的地方。在try中调用了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));
//index = 0
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
return chain.proceed(originalRequest);
}
从名字可以看出,与拦截器有关。首先创建了一个拦截器列表interceptors,并向其中添加了一系列的拦截器。紧接着创建了一个RealInterceptorChain对象,注意其构造函数中第5个参数index传入了0。然后调用了proceed()方法。这是一个接口Interceptor.Chain中的方法,由实现了该接口的类来具体实现,这里是RealInterceptorChain类。
public interface Interceptor {
Response intercept(Chain chain) throws IOException;
interface Chain {
Request request();
Response proceed(Request request) throws IOException;
...
}
}
调用了RealInterceptorChain类的proceed()方法。
@Override public Response proceed(Request request) throws IOException {
return proceed(request, streamAllocation, httpCodec, connection);
}
进到proceed()方法。
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
calls++;
...
// Call the next interceptor in the chain.
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
...
return response;
}
直接看主要代码,又创建了一个RealInterceptorChain对象,但是注意到构造方法第五个参数index传入的是index + 1。然后从拦截器列表中取出第index项,默认情况用户没有添加自定义拦截器时,第一次取出的拦截器为重定向拦截器RetryAndFollowUpInterceptor。因为这些默认的拦截器类都是实现了Interceptor接口。所以这里调用的是RetryAndFollowUpInterceptor类的intercept()方法。
@Override public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Call call = realChain.call();
EventListener eventListener = realChain.eventListener();
StreamAllocation streamAllocation = new StreamAllocation(client.connectionPool(),
createAddress(request.url()), call, eventListener, callStackTrace);
this.streamAllocation = streamAllocation;
int followUpCount = 0;
Response priorResponse = null;
while (true) {
if (canceled) {
streamAllocation.release();
throw new IOException("Canceled");
}
Response response;
boolean releaseConnection = true;
try {
//调用了RealInterceptorChain的proceed()方法
response = realChain.proceed(request, streamAllocation, null, null);
releaseConnection = false;
} catch (RouteException e) {
// The attempt to connect via a route failed. The request will not have been sent.
if (!recover(e.getLastConnectException(), streamAllocation, false, request)) {
throw e.getFirstConnectException();
}
releaseConnection = false;
continue;
} catch (IOException e) {
// An attempt to communicate with a server failed. The request may have been sent.
boolean requestSendStarted = !(e instanceof ConnectionShutdownException);
if (!recover(e, streamAllocation, requestSendStarted, 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.
if (priorResponse != null) {
response = response.newBuilder()
.priorResponse(priorResponse.newBuilder()
.body(null)
.build())
.build();
}
Request followUp;
try {
followUp = followUpRequest(response, streamAllocation.route());
} catch (IOException e) {
streamAllocation.release();
throw e;
}
if (followUp == null) {
streamAllocation.release();
return response;
}
closeQuietly(response.body());
if (++followUpCount > MAX_FOLLOW_UPS) {
streamAllocation.release();
throw new ProtocolException("Too many follow-up requests: " + followUpCount);
}
if (followUp.body() instanceof UnrepeatableRequestBody) {
streamAllocation.release();
throw new HttpRetryException("Cannot retry streamed HTTP body", response.code());
}
if (!sameConnection(response, followUp.url())) {
streamAllocation.release();
streamAllocation = new StreamAllocation(client.connectionPool(),
createAddress(followUp.url()), call, eventListener, callStackTrace);
this.streamAllocation = streamAllocation;
} else if (streamAllocation.codec() != null) {
throw new IllegalStateException("Closing the body of " + response
+ " didn't close its backing stream. Bad interceptor?");
}
request = followUp;
priorResponse = response;
}
}
发现再次调用了realChain的proceed()方法,而这个realChain正是我们创建的那个第五个参数为index + 1的对象。重新回到RealInterceptorChain类中的proceed()方法中,这里就不贴代码了,直接看上面的。重复的流程,构造方法中将index加1,interceptors.get(index)获取到下一个拦截器。interceptors列表中下一个拦截器是
BridgeInterceptor桥接拦截器,和前面RetryAndFollowUpInterceptor一样的套路,直接进到
BridgeInterceptor类的intercept()方法。
@Override public Response intercept(Chain chain) throws IOException {
Request userRequest = chain.request();
Request.Builder requestBuilder = userRequest.newBuilder();
RequestBody body = userRequest.body();
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.
boolean transparentGzip = false;
if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == 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());
}
//添加了一些请求头,继续调用proceed()
Response networkResponse = chain.proceed(requestBuilder.build());
HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());
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);
String contentType = networkResponse.header("Content-Type");
responseBuilder.body(new RealResponseBody(contentType, -1L, Okio.buffer(responseBody)));
}
return responseBuilder.build();
}
发现一样的套路,接着会调用下一个拦截器的intercept()方法。这其实是一个责任链模式,通过每次创建RealInterceptorChain对象时将index加1,不断取出并执行interceptors队列中的下一个拦截器,完全是按着一开始的加入顺序执行的。在经过各个拦截器一系列的处理后,在最后一个CallServerInterceptor拦截器中,访问了网络并得到了网络的相应。
而且可以发现,当最终得到来自网络的响应后,会按着请求时经过拦截器顺序的反序再过一遍拦截器,做一些处理。大体流程如下图所示。
总结
整个OkHttp请求网络的流程大体分析了一下。个人觉得可以分为三部分
- 通过两个工厂方法模式创建了Request和OkHttp对象
- 通过模板方法模式调用了线程池,发起不同的异步网络请求
- 通过责任链模式对网络请求和响应添加拦截器
有什么不对的地方欢迎大家指出。