一、okhttp简介
OKHttp是一个处理网络请求的开源项目,Android 当前最火热网络框架,由移动支付Square公司贡献,用于替代HttpUrlConnection和Apache HttpClient(android API23 6.0里已移除HttpClient)。现在在Android开发中最火的应用最多的联网框架毫无疑问是okhttp,目前已经大量替代了Volley、HttpUrlConnection。
二、okhttp用法
1)导包:
compile 'com.squareup.okhttp3:okhttp:3.9.1'
2)通过Builder类实例化客户端类OkhttpClient。
private val client: OkHttpClient by lazy {
OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.build()
}
实例化OkhttpClient时可以通过Builder类添加一系列客户端参数。
3)通过Builder类实例化请求类Request,通过OkHttpClient的newCall方法执行请求。
fun get(url: String, callBack: ResponseCallBack) {
var request = Request.Builder()
.url(Api.baseUrl + url)
.build()
client.newCall(request).enqueue(
object : Callback {
override fun onFailure(call: Call, e: IOException) {
callBack?.onFail(e.toString())
}
override fun onResponse(call: Call, response: Response) {
callBack?.onSuccess(response.body()!!.string())
}
}
)
}
fun post(url: String, requestParams: RequestParams, callBack: ResponseCallBack) {
var requestBody = FormBody.Builder()
requestParams.forEach {
requestBody.add(it.key, it.value.toString())
}
var request = Request.Builder()
.url(Api.baseUrl + url)
.post(requestBody.build())
.build()
client.newCall(request).enqueue(
object : Callback {
override fun onFailure(call: Call, e: IOException) {
callBack?.onFail(e.toString())
}
override fun onResponse(call: Call, response: Response) {
callBack?.onSuccess(response.body()!!.string())
}
}
)
}
实例化Request时可以通过Builder类添加一系列请求参数(例如Header信息),这里也不进行详细描述,在分析源码时进行具体分析。
4)同步、异步请求。execute()执行同步请求,enqueue()执行异步请求,同步请求方法返回Response,异步请求通过CallBack返回Response。
三、源码分析
1)OkHttpClient客户端类,主要看一下各个成员变量。
final Dispatcher dispatcher;//请求分发器,分发执行Request
final @Nullable Proxy proxy;//代理
final List<Protocol> protocols;//协议,管理协议版本
final List<ConnectionSpec> connectionSpecs;//传输层版本和连接协议
final List<Interceptor> interceptors;//拦截器
final List<Interceptor> networkInterceptors;//网络拦截器
final EventListener.Factory eventListenerFactory;//请求监听器
final ProxySelector proxySelector;//代理选择
final CookieJar cookieJar;//cookie
final @Nullable Cache cache;//缓存
final @Nullable InternalCache internalCache;//内部缓存
final SocketFactory socketFactory;//socket工厂
final @Nullable SSLSocketFactory sslSocketFactory;//HTTPS ssl安全套接层工厂
final @Nullable CertificateChainCleaner certificateChainCleaner;//验证证书
final HostnameVerifier hostnameVerifier;//确认主机名
final CertificatePinner certificatePinner;//证书链
final Authenticator proxyAuthenticator;//代理身份验证
final Authenticator authenticator;//本地身份验证
final ConnectionPool connectionPool;//连接池
final Dns dns;//DNS域名解析
final boolean followSslRedirects;//安全套接层重定向
final boolean followRedirects;//本地重定向
final boolean retryOnConnectionFailure;//连接失败重试
final int connectTimeout;//连接超时
final int readTimeout;//读取超时
final int writeTimeout;//写入超时
final int pingInterval;//ping命令时间间隔
可以看到所有成员变量都是final的,这样所有的变量赋值就全部交给Builder类,Builder类是OkHttpClient的静态内部类。可以通过builder()来完成设置,在不进行设置情况下会使用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;
}
2)Request请求信息类。成员变量如下:
final HttpUrl url;//请求url信息
final String method;//请求方式(post get)
final Headers headers;//请求header
final @Nullable RequestBody body;//请求Body
final Object tag;//请求tag
3)执行newCall()方法创建Call对象,Call接口唯一实现类是RealCall,是执行请求的真正对象。
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
// Safely publish the Call instance to the EventListener.
RealCall call = new RealCall(client, originalRequest, forWebSocket);
call.eventListener = client.eventListenerFactory().create(call);
return call;
}
RealCall请求类的源码如下:
final class RealCall implements Call {
final OkHttpClient client;
final RetryAndFollowUpInterceptor retryAndFollowUpInterceptor;//请求重定向拦截器
private EventListener eventListener;
final Request originalRequest;//request信息
final boolean forWebSocket;
// Guarded by this.
private boolean executed;
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
}
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
// Safely publish the Call instance to the EventListener.
RealCall call = new RealCall(client, originalRequest, forWebSocket);
call.eventListener = client.eventListenerFactory().create(call);
return call;
}
//同步请求
@Override 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);
}
}
.....
//异步请求
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
@Override public void cancel() {
retryAndFollowUpInterceptor.cancel();
}
@Override public synchronized boolean isExecuted() {
return executed;
}
@Override public boolean isCanceled() {
return retryAndFollowUpInterceptor.isCanceled();
}
@SuppressWarnings("CloneDoesntCallSuperClone") // We are a final type & this saves clearing state.
@Override public RealCall clone() {
return RealCall.newRealCall(client, originalRequest, forWebSocket);
}
StreamAllocation streamAllocation() {
return retryAndFollowUpInterceptor.streamAllocation();
}
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
String host() {
return originalRequest.url().host();
}
Request request() {
return originalRequest;
}
RealCall get() {
return RealCall.this;
}
@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 {
eventListener.callFailed(RealCall.this, e);
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
}
//链式请求方法
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
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);
}
先来分析同步请求,从源码中可以看到同步请求中会先通过
client.dispatcher().executed(this);
完成对请求的监听,本质上是将当前请求放入一个队列中,当请求结束之后再移除队列。
/** Running synchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
对于异步请求来说同样会进行请求的监听,唯一的区别在于异步请求是用两个队列完成,一个是等待请求的队列,一个是正在请求的队列。
/** Ready async calls in the order they'll be run. */
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
/** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
最终进行网络请求是通过链式方法getResponseWithInterceptorChain来完成的。这个方法也是网络请求的精髓所在。这个方法里通过获取设置的一系列拦截器来完成网络请求工作,每个拦截器有不同的分工。最后通过构建的拦截器链调用proceed()方法完成网络请求。由于不同的拦截器分别负责网络请求中的不同工作。分析起来内容比较多,这里先不进行具体各个拦截器的源码分析。
4)Dispatcher请求分发器,在okhttp中网络请求分发是通过Dispatcher分发器来维护的,Dispatcher控制着当前网络请求是否执行还是进入等待状态,这里涉及一些网络请求的域名等判断信息。Dispatcher类源码如下:
public final class Dispatcher {
private int maxRequests = 64;//最大请求数
private int maxRequestsPerHost = 5;//最大主机名
private @Nullable Runnable idleCallback;
private @Nullable ExecutorService executorService;//请求线程池,核心线程0,非核心线程最大值Integer.MAX_VALUE
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();//异步等待队列
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();//异步请求队列
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();//同步请求队列
.......
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
public synchronized void setMaxRequests(int maxRequests) {
if (maxRequests < 1) {
throw new IllegalArgumentException("max < 1: " + maxRequests);
}
this.maxRequests = maxRequests;
promoteCalls();
}
public synchronized int getMaxRequests() {
return maxRequests;
}
public synchronized void setMaxRequestsPerHost(int maxRequestsPerHost) {
if (maxRequestsPerHost < 1) {
throw new IllegalArgumentException("max < 1: " + maxRequestsPerHost);
}
this.maxRequestsPerHost = maxRequestsPerHost;
promoteCalls();
}
public synchronized int getMaxRequestsPerHost() {
return maxRequestsPerHost;
}
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
private void promoteCalls() {
if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall call = i.next();
if (runningCallsForHost(call) < maxRequestsPerHost) {
i.remove();
runningAsyncCalls.add(call);
executorService().execute(call);
}
if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
}
}
private int runningCallsForHost(AsyncCall call) {
int result = 0;
for (AsyncCall c : runningAsyncCalls) {
if (c.host().equals(call.host())) result++;
}
return result;
}
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
void finished(AsyncCall call) {
finished(runningAsyncCalls, call, true);
}
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();
}
}
public synchronized List<Call> runningCalls() {
List<Call> result = new ArrayList<>();
result.addAll(runningSyncCalls);
for (AsyncCall asyncCall : runningAsyncCalls) {
result.add(asyncCall.get());
}
return Collections.unmodifiableList(result);
}
public synchronized int queuedCallsCount() {
return readyAsyncCalls.size();
}
public synchronized int runningCallsCount() {
return runningAsyncCalls.size() + runningSyncCalls.size();
}
}
在同步请求时直接加入同步请求队列中,持有同步请求的请求引用。对于异步请求来讲,会判断当前正在执行的请求是否达到最大请求限制,并且正在执行请求的主机名是否达到个数限制,如果都没有达到限制,则立即通过线程池进行网络请求,否则放入异步等待队列。那么什么时候进行执行等待队列中的请求呢?
在一个网络请求结束之后会调用Dispatcher的finished方法,在finished方法中会调用promoteCalls()方法来判断时候可以执行等待队列中的网络请求。
文中demo代码:https://github.com/24KWYL/okhttp.git
网友评论