okhttp是一个非常好用的开源的网络请求框架,接下来我们就来简单分析一下okhttp的源码。
首先我们来大致看一下同步方法的使用,在这里我们以get方式为例
public static String get(String url, String json){
OkHttpClient okHttpClient=new OkHttpClient();
Request request = new Request.Builder()
.url(url)
.build();
Response response = null;
try {
response = okHttpClient
.newCall(request)
.execute();
if (response.isSuccessful()) {
return response.body().string();
}
} catch (IOException e) {
Log.i("tag",e.getMessage());
e.printStackTrace();
}
return "{'error':'错误'}";
}
我们首先创建了一个okHttpClient,然后又封装了Request请求,最后调用了okHttpClient的newCall(request).exexute()方法。这样就简单完成了一次访问服务器的请求。那么它内部到底是如何操作的呢?接下来我们就来分析一下源码。
public Call newCall(Request request) {
return new Call(this, request);
}
protected Call(OkHttpClient client, Request originalRequest){
this.client = client.copyWithDefaults();
this.originalRequest = originalRequest;
}
public Response execute() throws IOException {
synchronized(this) {
if(this.executed) {
throw new IllegalStateException("Already Executed");
}
this.executed = true;
}
Response var2;
try {
this.client.getDispatcher().executed(this);
Response result = this.getResponseWithInterceptorChain(false);
if(result == null) {
throw new IOException("Canceled");
}
var2 = result;
} finally {
this.client.getDispatcher().finished(this);
}
return var2;
}
下面我们就具体分析一下。
newCall()方法会最终调用Call类的构造函数new Call(),从而进行初始化。继而调用Call类的execute方法。在execute方法中,首先会先判断该请求是否已执行,若已执行,抛出异常,若没有执行则会调用Dispatcher.exexute()方法。Dispatcher就是一个分发器,它是okHttpClient的一个成员变量。下面是Dispatcher的成员变量的定义
private int maxRequests = 64;
private int maxRequestsPerHost = 5;
private ExecutorService executorService;
private final Deque<AsyncCall> readyCalls = new ArrayDeque();
private final Deque<AsyncCall> runningCalls = new ArrayDeque();
private final Deque<Call> executedCalls = new ArrayDeque();
Dispatcher类中使用了线程池,设置了最大的请求数等等
public synchronized ExecutorService getExecutorService() {
if(this.executorService == null) {
this.executorService = new ThreadPoolExecutor(
0,
2147483647,
60L,
TimeUnit.SECONDS,
new SynchronousQueue(),
Util.threadFactory("OkHttp Dispatcher", false));
}
return this.executorService;
}
由代码可以看出,这里创建了一个线程池,核心线程数为0,最大线程数为2147483647,空闲时间为60s。在这里就不具体讲解该线程池。
接着回到exexute方法中,dispatcher的exexute方法会将该call请求放入队列中
synchronized void executed(Call call) {
this.executedCalls.add(call);
}
然后会调用getResponseWithInterceptorChain()方法,最后执行完毕会将请求从队列中移除,即 this.client.getDispatcher().finished(this);
接着我们具体分析getResponseWithInterceptorChain()方法,getResponseWithInterceptorChain是真正完成请求的方法。
private Response getResponseWithInterceptorChain(boolean forWebSocket) throws IOException {
Call.ApplicationInterceptorChain chain = new Call.ApplicationInterceptorChain(0, this.originalRequest, forWebSocket);
return chain.proceed(this.originalRequest);
}
class ApplicationInterceptorChain implements Chain {
private final int index;
private final Request request;
private final boolean forWebSocket;
ApplicationInterceptorChain(int index, Request request, boolean forWebSocket) {
this.index = index;
this.request = request;
this.forWebSocket = forWebSocket;
}
public Connection connection() {
return null;
}
public Request request() {
return this.request;
}
public Response proceed(Request request) throws IOException {
if(this.index < Call.this.client.interceptors().size()) {
Call.ApplicationInterceptorChain chain = Call.this.new ApplicationInterceptorChain(this.index + 1, request, this.forWebSocket);
return ((Interceptor)Call.this.client.interceptors().get(this.index)).intercept(chain);
} else {
return Call.this.getResponse(request, this.forWebSocket);
}
}
}
首先先创建一个拦截器对象链,然后调用其proceed方法。在proceed方法中,如果有拦截器,则会由拦截器依次处理,处理完毕以后调用getResponse()方法。getResponse方法中做了如下操作:将request封装成HttpEngine,由HttpEngine发送请求和接收回应,接收成功以后,释放链接,返回response
最后总结一下,okHttp的流程图