发起一个简单的Okhttp请求:
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
Request request = new Request
.Builder()
.url("https://www.baidu.com")
.build();
okhttp3.Call call = okHttpClient.newCall(request);
同步请求
//call.execute();
//异步请求
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.e("tag", "请求失败");
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) {
Log.e("tag", "请求成功");
}
});
构建Okhttp的几个基础类:
Request:请求方法、请求头、参数、请求体等基础参数的封装类
OkhttpClient:用于构建Call请求的工厂类,用于配置请求如超时时间、缓存、https证书验证、拦截器等,内部还封装了用于分发请求的Dispatcher类、Socket工厂类、Socket连接池等。
Call:请求的发起、取消、结果返回、状态回调,是Okhttp请求的控制类
Okhttp请求执行的基本流程如下图:
同步请求
Call的实现类RealCall调用execute()发起同步请求,接着调用getResponseWithInterceptorChain()方法获取同步响应结果,此方法的具体实现后面统一分析
@Override
public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
transmitter.timeoutEnter();
transmitter.callStart();
try {
client.dispatcher().executed(this);
return getResponseWithInterceptorChain();
} finally {
client.dispatcher().finished(this);
}
}
异步请求
RealCall调用enqueue()方法发起异步请求,实际上是通过其内部保存的OkhttpClient引用,获取到请求分发器Dispacher,创建RealCall的内部类AsyncCall对象(其实是一个Runnable对象),添加到请求队列中
class RealCall{
......
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
transmitter.callStart();
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
.......
}
接下来看一下Dispatcher中的实现,它内部封装了线程池、待执行的、执行中的同步/异步请求队列以及请求数量的限制条件
public final class Dispatcher {
private int maxRequests = 64;
private int maxRequestsPerHost = 5;
private @Nullable Runnable idleCallback;
private @Nullable ExecutorService executorService;
//待执行的异步请求队列
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
//正在执行的异步请求
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
//正在执行的同步请求
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
public Dispatcher(ExecutorService executorService) {
this.executorService = executorService;
}
public Dispatcher() {
}
//创建线程池
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
//添加请求到待执行队列
void enqueue(AsyncCall call) {
synchronized (this) {
readyAsyncCalls.add(call);
// Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to
// the same host.
if (!call.get().forWebSocket) {
AsyncCall existingCall = findExistingCallWithHost(call.host());
if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
}
}
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();
//最大支持同时64个异步请求
if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
//同一host下最大支持同时5个异步请求
if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity.
i.remove();
//统计同一host下同时请求个数
asyncCall.callsPerHost().incrementAndGet();
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;
}
......
}
接着看异步请求的执行流程,上述代码第30行Dispatcher调用enqueue()方法将AsyncCall添加到待执行的请求队列,第41行调用promoteAndExecute()真正将请求添加到线程池执行。
从方法内部可以看到Okhttp对于并发数量是有限制的,最大同时执行的请求数量为64个,同一host下最多可以同时执行5个请求。
最后遍历可执行的请求,逻辑从Dispatcher类中切换到AsyncCall中,AsyncCall本身又是一个Runnable,它的最终执行逻辑一定是在run()方法中实现的,跟踪代码可以看到它的逻辑切换流程executeOn(executorService) --> run() --> execute()
@Override
protected void execute() {
boolean signalledCallback = false;
transmitter.timeoutEnter();
try {
//发起请求返回响应结果
Response response = getResponseWithInterceptorChain();
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);
}
}
这里的代码和同步请求RealCall中execute()非常相似,同样是调用getResponseWithInterceptorChain()获取响应结果,只不过异步请求的Response回调执行在子线程中。
拦截器(Interceptor)
无论是同步请求还是异步请求都是调用getResponseWithInterceptorChain()获取响应结果,方法命名很直观,通过拦截器链来获取响应。
Response getResponseWithInterceptorChain() throws IOException {
//将各种拦截器添加到集合
List<Interceptor> interceptors = new ArrayList<>();
//添加自定义的请求拦截器
interceptors.addAll(client.interceptors());
//添加失败重试和重定向拦截器
interceptors.add(new RetryAndFollowUpInterceptor(client));
//添加网络桥拦截器,用户添加默认的请求头等信息
interceptors.add(new BridgeInterceptor(client.cookieJar()));
//添加缓存拦截器
interceptors.add(new CacheInterceptor(client.internalCache()));
//添加连接拦截器,给当前请求创建或者从缓存里获取一个可用连接(建立socket连接)
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
//添加自定义的网络拦截器
interceptors.addAll(client.networkInterceptors());
}
//添加请求服务拦截器,真正发起请求通过io流获取响应信息(通过socket连接发送数据以及接受响应)
interceptors.add(new CallServerInterceptor(forWebSocket));
//构建拦截器链的头节点
Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
originalRequest, this, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
boolean calledNoMoreExchanges = false;
try {
/*
* 开始拦截器链的执行,根据index获取拦截器执行intercept()方法,intercept()内部通过自增的index参数构建新的拦截器链节点,
* 通过其调用proceed()又开启下一个拦截器的处理,这样就构成了一个完整的循环遍历执行拦截器的过程
*/
Response response = chain.proceed(originalRequest);
if (transmitter.isCanceled()) {
closeQuietly(response);
throw new IOException("Canceled");
}
return response;
} catch (IOException e) {
calledNoMoreExchanges = true;
throw transmitter.noMoreExchanges(e);
} finally {
if (!calledNoMoreExchanges) {
transmitter.noMoreExchanges(null);
}
}
}
}
方法内部定义了Interceptor集合依次将以下拦截器添加到集合中:
自定义Interceptor:我们自己实现的拦截器,比如我们有时候想要在请求前统一添加公共参数或者添加请求、响应的日志都可以自定义拦截器来实现;
RetryAndFollowUpInterceptor:实现了失败重试和重定向的一些策略;
BridgeInterceptor:处理我们添加的请求头以及添加一些默认请求头信息如gzip透明压缩等;
CacheInterceptor:处理缓存策略的一些逻辑;
ConnectInterceptor:创建Socket和服务器进行连接,维护Socket连接池;有兴趣的朋友可以跟以下这个拦截器的代码它最终创建Socket连接实在RealConnection类中实现的
自定义NetworkInterceptor:通常用于监听Socket连接内容,如Facebook出品的Stetho,可以很方便的让我们通过浏览器调试接口
CallServerInterceptor:向Socket连接发送请求数据并且获取响应数据,它底层用Okio库替代了Java原生的io流操作。
getResponseWithInterceptorChain()方法内部创建了一个重要的对象RealInterceptorChain,它的构造函数会传入一个index,这个index正是下一个所要执行的拦截器在集合中的下标,process()方法每调用依次index都会随之递增,而每个Interceptor的intercept()方法中又会调用RealInterceptorChain的process()方法,这样就达到了遍历执行Intercepter的目的
public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange)
throws IOException {
......
// 执行下一个拦截器的代码
RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
......
return response;
}
如上图所示,拦截器链在遍历执行的过程中,依次对Request进行拦截处理最后获取到响应后又沿着相反的方向将Response返回,在返回的过程中拦截器又可以逐层最Response进行处理,将最终结果返回给Call对象,这样就完成一个完整的Okhttp请求流程。