同样的,第一步肯定是创建OkHttpClient客户端:
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
我们先看Builder()构造方法:
public Builder() {
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
eventListenerFactory = EventListener.factory(EventListener.NONE);
proxySelector = ProxySelector.getDefault();
cookieJar = CookieJar.NO_COOKIES;
socketFactory = SocketFactory.getDefault();
hostnameVerifier = OkHostnameVerifier.INSTANCE;
certificatePinner = CertificatePinner.DEFAULT;
proxyAuthenticator = Authenticator.NONE;
authenticator = Authenticator.NONE;
connectionPool = new ConnectionPool();
dns = Dns.SYSTEM;
followSslRedirects = true;
followRedirects = true;
retryOnConnectionFailure = true;
connectTimeout = 10*000;
readTimeout = 10*000;
writeTimeout = 10*000;
pingInterval = 0;
}
在这个方法中,初始化了许多的参数,其中:
Dispatcher:在异步请求中,它决定这时立即处理还是缓存等待,并在有结果之后进行线程的切换。在同步请求中,他仅仅是把请求加入到队列当中,不做太多的操作。
connectionPool = new ConnectionPool():connectionPool是一个连接池,他统一对我们发起的网络请求进行管理,当我们请求的URL相同的时候,他就会知道这个URL请求是可以复用的,不用再创建。然后还实现了对网络连接状态的处理和管理:那些网络请求可以保持打开状态,那些请求是可以复用的。
第二步,我们再来看看Request报文请求对象的创建:
Request request = new Request.Builder().addHeader(key, value).build();
他也是使用建造者模式创建的,我们先看看他的Builder的构造方法Builder():
public Builder() {
this.method = "GET";
this.headers = new Headers.Builder();
}
只有两行有效代码,一是指定请求方式“”GET,二是创建请求头的对象,方便我们添加header头文件。当然他的Request有参构造方法就复杂些了:
Builder(Request request) {
this.url = request.url;
this.method = request.method;
this.body = request.body;
this.tag = request.tag;
this.headers = request.headers.newBuilder();
}
其实也比较简单。主要就是设置几个常用的参数:URL请求连接,请求方法,GET还是POST,设置请求标识,设置请求头。
然后他的.Build()方法源码如下:
public Request build() {
if (url == null) throw new IllegalStateException("url == null");
return new Request(this);
}
就是创建一个Request对象,并把我们前面给Builder设置的各种参数传进去
第三步,就是创建Call对象:
Call call = client.newCall(mRequest);
newCall()方法如下:
public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false);
}
在这里,我们要重点关注的是RealCall这个对象,他的构造方法如下:
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
RealCall call = new RealCall(client, originalRequest, forWebSocket);
call.eventListener = client.eventListenerFactory().create(call);
return call;
}
第一个操作是调用RealCall的有参构造,创建RealCall对象:
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
}
这里面,他持有前面两步创建的OkHttpClient客户端对象和Request对象。并创建了一个RetryAndFollowUpInterceptor拦截器对象。
第二个操作是给Call对象设置事件监听。
这里我们需要注意的是,这里的三个步骤,其实无论是同步请求还是异步请求,都是一样的。区别在于第四步:通过Call调用请求方法:execute()/enqueue().
这里我们先看看execute()方法的源码:
Call是一个接口,execute()/enqueue()方法的具体实现由 他的实现类RealCall来实现:
public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
eventListener.callFailed(this, e);
throw e;
} finally {
client.dispatcher().finished(this);
}
}
这是一个用synchronized加了锁的线程安全的方法,锁里面的if判断的标识executed 意思是同一个请求只会执行一次,反复调用的时候,第一次调用的时候就会执行executed=true,然后后面在调用的时候,就回你抛出new IllegalStateException(“Already Executed”)异常。
然后会调用eventListener.callStart(this)开始一个监听事件,无论调用execute()还是enqueue()都会开启这个监听。
然后就是调用client.dispatcher().executed(this),作用是:
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
也就是把call请求添加到请求队列中去。runningSyncCalls对象是这样的:
Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
然后就是Response result = getResponseWithInterceptorChain();这个里面就是根据拦截器设定的规则拦截掉不需要的信息,然后返回我们需要的结果。
Response getResponseWithInterceptorChain() throws IOException {
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));
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
return chain.proceed(originalRequest);
}
}
当我们的请求技术后,会执行finally里面的结果:目的是回收我们的请求,以便复用或者清理状态
finally {
client.dispatcher().finished(this);
}
Finished()方法主要干了这些事情:
void finished(RealCall call) {
finished(runningSyncCalls, call, false);
}
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!");
if (promoteCalls) promoteCalls();
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
}
在synchronized同步代码块里面,会首先移除已经执行完毕的call,如果不能移除,就会抛出异常,然后判断promoteCalls参数,由于在同步请求里面promoteCalls=false,所以promoteCalls()不会执行,但是在异步请求里面,promoteCalls=true,会执行promoteCalls()方法。然后再调用runningCallsCount()方法计算当前队列里面正在执行的请求call的数量:
public synchronized int runningCallsCount() {
return runningAsyncCalls.size() + runningSyncCalls.size();
}
最后再把正在执行的idleCallback线程重新赋值一份。用于后面的判断。最后再执行最后的if判断:如果正在执行的请求书为0,也就是我们的dispatcher分发器里面已经没有可运行的请求了,同时idleCallback不为空的时候,调用run方法,结束请求。
其实dispatcher在同步请求里面作用很简单:把call请求添加到队列,完成后再把call请求移除队列。Dispatcher主要作用在异步请求里面。