首先看一下Okhttp3是怎么进行请求的
//创建OkHttpClient对象
OkHttpClient client = new OkHttpClient.Builder().readTimeout(5, TimeUnit.SECONDS)
.writeTimeout(5, TimeUnit.SECONDS)
.connectTimeout(5, TimeUnit.SECONDS).build();
Request request = new Request.Builder().url("www.baidu.com").get().build();//创建Request对象
Call call = client.newCall(request);//将Request封装成Call 再用Call进行同步或者异步请求
同步请求:
//同步 :开始请求后就会进入阻塞状态,直接接到响应
try {
Response response = call.execute();//响应报文的信息,比如响应头,体...
} catch (IOException e) {
e.printStackTrace();
}
异步请求:
//异步 :不会阻塞当前线程
call.enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
}
});
以上就是Okhttp的用法,接下来我们来分析一下请求里面做了什么操作
先看一下client.newCall(request)这个方法
@Override public Call newCall(Request request) {
return new RealCall(this, request, false /* for web socket */);
}
其实是创建了RealCall类,再跟进new RealCall里面看下
RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
//将client和之前创建的request在这里面进行了赋值,并且创建了一个拦截器RetryAndFollowUpInterceptor(也叫重定向拦截器,后面会再进行分析)
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);
}
再进一步看看call.execute()里面是怎么操作的(其实就是在RealCall里面具体实现)看如下代码
@Override public Response execute() throws IOException {
synchronized (this) {
//这个代码就是让同一个请进只能进行一次操作
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
try {
client.dispatcher().executed(this);//用dispatcher(调度器)分配执行的任务
Response result = getResponseWithInterceptorChain();//获取响应报文和一些拦截器操作,以后会重点介绍
if (result == null) throw new IOException("Canceled");
return result;
} finally {
client.dispatcher().finished(this);
}
}
再看看Dispatch的executed方法
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>(); 通过dispahch将call请求添加到了同步请求队列里面,很简单
//dispatch的executed方法
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
再看一下异步的方法
call.enqueue(CallBack)
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
看看dispatcher的enqueque,跟同步就大不一样,看以下几个方法
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();//正在执行的异步请求队列 private int maxRequests = 64;//最大的请求队列 private int maxRequestsPerHost = 5;//最大请求主机数 private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();//异步缓存队列
synchronized void enqueue(AsyncCall call) {
//如果正在执行的异步请求队列小于最大的请求队列 及 最大的请求主机数小于设置值时 则将任务添加到正在执行的异步队列中然后执行
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);//创建线程池并且执行该任务
} else {//同理将其添加到缓存队列中
readyAsyncCalls.add(call);
}
}
public synchronized ExecutorService executorService() {//创建线程池
if (executorService == null) {
//0:当核心线程数为0时,一段时间后会将里面的所有线程给清掉;Integer.MAX_VALUE最大的线程数其实在okhttp3里面不会超过64; 60:大于核心线程数时,每个线程最长的存活时间60S
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false
}
return executorService;
}
异步方法执行任务最终也会调用到getRequestWithInterseptorChain方法中,我们在调用异步请求时会将Callback封装成AsynCall,其实AsynCall继承NamedRunnable最终继承Runnable 当执行请求任务时就会调用到AsynCall的execute()方法,其实当线程池执行队列任务里就会执行asynCall的run方法 以下是代码AsynCall的execute()方法代码
@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);//最终都会走到这,将任务结束掉
}
}
void finished(AsyncCall call) {//异步结束任务的代码
finished(runningAsyncCalls, call, true);
}
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
int runningCallsCount;
Runnable idleCallback;
synchronized (this) {//同步
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");//先将任务remove掉
if (promoteCalls) promoteCalls();//异步promoteCalls传过来的是true,如果会走promoteCalls()方法,就是对任务进行重新排列
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
}
//将异步正在执行的任务队列和缓存队列任务进行重新排列
private void promoteCalls() {
if (runningAsyncCalls.size() >= maxRequests) return; // 大于64return
if (readyAsyncCalls.isEmpty()) return; //缓存队列没有任务,return
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall call = i.next();//取到第一个缓存队列里的任务
if (runningCallsForHost(call) < maxRequestsPerHost) {//判断请求主机数是否大于5
i.remove();//将任务从缓存队列中移除
runningAsyncCalls.add(call);//再添加到异步执行队列中
executorService().execute(call);//最后在线程池中执行该任务
}
if (runningAsyncCalls.size() >= maxRequests) return; // 正在执行的队列大小小>=64 结束循环
}
}
所以异步缓存队列里的任务是在promoteCalls方法中执行的.
Okhttp3网络请求简单的分析到这也就结束了,有时间再对里面再具体的细节进行分析