网络请求框架很多,这里记录一下Okhttp。它的功能非常强大,在很多项目中使用。一直很好奇它的内部实现,下面就来看看:
Okhttp基本用法:
//创建client
OkHttpClient mOkHttpClient = new OkHttpClient();
//builder模式构造Request
Request mRequest = new Request.Builder()
.url(“http://www.baidu.com”)
.build();
//通过OkHttpClient的方法newCall将Request封装到Call中
Call call = mOkHttpClient.newCall(mRequest);
//异步请求
call.enqueue(new Callback(){
@Override
public void onFailure(Request request, IOException e) {
//TODO 请求失败的回调
}
@Override
public void onResponse(Response response){
//TODO 请求成功的回调
}
});
嗯,基本用法很简单。其实内部实现主要是Request的创建和发送,以及Response的获取。
一、Request创建
Request内部类Builder
public static class Builder {
private HttpUrl url;
private String method;
private Headers.Builder headers;
private RequestBody body;
private Object tag;
public Builder() {
this.method = "GET";//默认是get
this.headers = new Headers.Builder();//头部也是使用Builder模式构造的
}
public Builder url(String url) {
if (url == null) throw new IllegalArgumentException("url == null");
// Silently replace websocket URLs with HTTP URLs.
if (url.regionMatches(true, 0, "ws:", 0, 3)) {
url = "http:" + url.substring(3);
} else if (url.regionMatches(true, 0, "wss:", 0, 4)) {
url = "https:" + url.substring(4);
}
HttpUrl parsed = HttpUrl.parse(url);
if (parsed == null) throw new IllegalArgumentException("unexpected url: " + url);
return url(parsed);
}
public Builder url(HttpUrl url) {
if (url == null) throw new IllegalArgumentException("url == null");
this.url = url;
return this;
}
public Request build() {
if (url == null) throw new IllegalStateException("url == null");
return new Request(this);
}
至此,Request创建完成。
二、Request的发送
public OkHttpClient() {
routeDatabase = new RouteDatabase();
dispatcher = new Dispatcher();
}
public Call newCall(Request request) {
return new Call(this, request);
}
protected Call(OkHttpClient client, Request originalRequest) {
// Copy the client. Otherwise changes (socket factory, redirect policy,
// etc.) may incorrectly be reflected in the request when it is executed.
this.client = client.copyWithDefaults();//复制客户端,并赋值给当前对象
this.originalRequest = originalRequest;
}
通过OkHttpClient中的newCall方法将Request封装到Call中,然后调用Call中的异步方法enqueue执行异步请求
public void enqueue(Callback responseCallback) {
enqueue(responseCallback, false);
}
void enqueue(Callback responseCallback, boolean forWebSocket) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
//调用Dispatcher的enqueue方法,并将回调方法封装在AsyncCall中
client.getDispatcher().enqueue(new AsyncCall(responseCallback, forWebSocket));
}
先看看Dispatcher——-调度器
Public class Dispatcher{
//最大请求数
private int maxRequests = 64;
//发送给每台主机的最大请求数
private int maxRequestsPerHost = 5;
/** Executes calls. Created lazily. */
private ExecutorService executorService;//线程池
/** Ready calls in the order they'll be run. */
private final Deque<AsyncCall> readyCalls = new ArrayDeque<>();//等待队列
/** Running calls. Includes canceled calls that haven't finished yet. */
private final Deque<AsyncCall> runningCalls = new ArrayDeque<>();//运行队列
/** In-flight synchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<Call> executedCalls = new ArrayDeque<>();
public Dispatcher(ExecutorService executorService) {
this.executorService = executorService;
}
//在构造OkHttpClient时已经调用了 下面这个构造方法
public Dispatcher() {
}
synchronized void enqueue(AsyncCall call) {
if (runningCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
//如果正在执行的请求数小于最大请求数,并且发送给每台主机的请求数也小于规定数,就将当前Request添加到执行队列,可以立即执行。
runningCalls.add(call);
getExecutorService().execute(call);//线程池调用子线程来异步执行任务
} else {
readyCalls.add(call);//将当前Request放入等待队列
}
}
}
接下来看看AsyncCall
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
private final boolean forWebSocket;
private AsyncCall(Callback responseCallback, boolean forWebSocket) {
super("OkHttp %s", originalRequest.urlString());
this.responseCallback = responseCallback;
this.forWebSocket = forWebSocket;
}
//.......省略中间代码
//实现父类中的方法
@Override protected void execute() {
boolean signalledCallback = false;
try {
//获取response,重点方法。。。。。。。
Response response = getResponseWithInterceptorChain(forWebSocket);
if (canceled) {
signalledCallback = true;
responseCallback.onFailure(originalRequest, new IOException("Canceled"));//失败的回调
} else {
signalledCallback = true;
responseCallback.onResponse(response);//成功的回调
}
} catch (IOException e) {
if (signalledCallback) {
// Do not signal the callback twice!
} else {
responseCallback.onFailure(engine.getRequest(), e);//失败的回调
}
} finally {
client.getDispatcher().finished(this);//不管怎样,最终都要将request处理掉
}
}
}
AsyncCall中没有run方法,那怎么运行呢???不急,这时候该去看看它的父类,NamedRunnable中必须有run方法啊 ,,,
public abstract class NamedRunnable implements Runnable {
protected final String name;
public NamedRunnable(String format, Object... args) {
this.name = String.format(format, args);
}
//很熟悉的方法,,,
@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();//抽象方法,在子类AsyncCall中具体实现
}
三、获取Response
//调用getResponseWithInterceptorChain
private Response getResponseWithInterceptorChain(boolean forWebSocket) throws IOException {
Interceptor.Chain chain = new ApplicationInterceptorChain(0, originalRequest, forWebSocket);
return chain.proceed(originalRequest);
}
class ApplicationInterceptorChain implements Interceptor.Chain {
@Override public Response proceed(Request request) throws IOException {
if (index < client.interceptors().size()) {
// 拦截,先做一些预处理
Interceptor.Chain chain = new ApplicationInterceptorChain(index + 1, request, forWebSocket);
return client.interceptors().get(index).intercept(chain);
} else {
//没有需要拦截的信息时,就走http请求
return getResponse(request, forWebSocket);
}
}
}
//通过getResponse方法,执行request,获取response
Response getResponse(Request request, boolean forWebSocket) throws IOException {
// Copy body metadata to the appropriate request headers.
//首先,通过该Request来填充RequestBody的头信息:contentType,contentLength,Transfer-Encoding
RequestBody body = request.body();
if (body != null) {
Request.Builder requestBuilder = request.newBuilder();
//......就是填充header的,不是重点
request = requestBuilder.build();
}
//创建HttpEngine,这是重点
engine = new HttpEngine(client, request, false, false, forWebSocket, null, null, null, null);
int followUpCount = 0;
while (true) {
if (canceled) {
engine.releaseConnection();
throw new IOException("Canceled");
}
try {
engine.sendRequest();//发送request
engine.readResponse();//读取response
} catch (RequestException e) {
throw e.getCause();
} catch (RouteException e) {
HttpEngine retryEngine = engine.recover(e);
if (retryEngine != null) {
engine = retryEngine;
continue;
}
throw e.getLastConnectException();
} catch (IOException e) {
HttpEngine retryEngine = engine.recover(e, null);
if (retryEngine != null) {
engine = retryEngine;
continue;
}
throw e;
}
Response response = engine.getResponse();
Request followUp = engine.followUpRequest();//处理重定向
if (followUp == null) {
if (!forWebSocket) {
engine.releaseConnection();
}
return response;
}
// followUpCount次数不能太多
if (++followUpCount > MAX_FOLLOW_UPS) {
throw new ProtocolException("Too many follow-up requests: " + followUpCount);
}
if (!engine.sameConnection(followUp.httpUrl())) {
engine.releaseConnection();
}
Connection connection = engine.close();
request = followUp;
engine = new HttpEngine(client, request, false, false, forWebSocket, connection, null, null,
response);
}
}