okhttp源码分析
一、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 protocols;//协议,管理协议版本 final List connectionSpecs;//传输层版本和连接协议 final List interceptors;//拦截器 final List 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 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 runningSyncCalls = new ArrayDeque<>();
对于异步请求来说同样会进行请求的监听,唯一的区别在于异步请求是用两个队列完成,一个是等待请求的队列,一个是正在请求的队列。
/** Ready async calls in the order they'll be run. */ private final Deque readyAsyncCalls = new ArrayDeque<>(); /** Running asynchronous calls. Includes canceled calls that haven't finished yet. */ private final Deque 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 readyAsyncCalls = new ArrayDeque<>();//异步等待队列 private final Deque runningAsyncCalls = new ArrayDeque<>();//异步请求队列 private final Deque runningSyncCalls = new ArrayDeque<>();//同步请求队列....... public synchronized ExecutorService executorService() { if (executorService == null) { executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS, new SynchronousQueue(), 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 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 void finished(Deque 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 runningCalls() { List 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
更多相关文章
- 关于Android(安卓)5.0 网络图标叹号的解决办法
- Android——常用的系统服务
- Android(安卓)Volley 源码解析
- Android之网络访问(一)android 中对apache httpclient及httpurlc
- Java集合 && Android提供的集合
- 【Tech-Android-View】Android中可以使用的网络音乐资源(榜单 歌
- Android文档学习05_网络1
- Android(安卓)AsyncTask两种线程池分析和总结
- android Webview加载网络图片