Android OkHttp(三)源码解析
来源:互联网 发布:c语言源文件名有那些 编辑:程序博客网 时间:2024/05/16 09:37
前面两篇文章,我们介绍了OKHttp的基本用法,今天这篇文章将从OkHttp源码的角度来分析OkHttp的整个工作流程。
初始化一个OkHttpClient对象,
OkHttpClient mOkHttpClient = new OkHttpClient();
OkHttpClient的构造函数中又初始化了一个Builder对象,
public OkHttpClient() { this(new Builder()); }
Builder的构造函数中,默认会创建对象以及一些属性,Builder对象是用来构造网络请求的。这种设计模式和Android的对话框中的Builder几乎是一个意思。
public Builder() { dispatcher = new Dispatcher(); protocols = DEFAULT_PROTOCOLS; connectionSpecs = DEFAULT_CONNECTION_SPECS; 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; }接着,创建一个请求,
Request request = new Request.Builder() .url(url) .build();Request类是HTTP请求,它携带了请求地址、请求方法、请求头部、请求体以及其他信息。它也是通过Builder模式创建的。Request.Builder().build()源码,
public Request build() { if (url == null) throw new IllegalStateException("url == null"); return new Request(this); }Request的构造方法,
private Request(Builder builder) { this.url = builder.url; this.method = builder.method; this.headers = builder.headers.build(); this.body = builder.body; this.tag = builder.tag != null ? builder.tag : this; }发起请求有两种方式,一种是同步,一种是异步,下面分别看看如何实现,
同步请求,
Response response = mOkHttpClient.newCall(request).execute();Response是HTTP响应,它继承自Closeable(Closeable继承自AutoCloseable,AutoCloseable资源自动关闭的接口),它携带了请求、网络请求协议、返回状态码、请求头、响应体等等,其中,网络请求协议是Protocol,Protocol是一个枚举类型,包含4中类型,
public enum Protocol { /** * An obsolete plaintext framing that does not use persistent sockets by default. */ HTTP_1_0("http/1.0"), /** * A plaintext framing that includes persistent connections. * * <p>This version of OkHttp implements <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC * 2616</a>, and tracks revisions to that spec. */ HTTP_1_1("http/1.1"), /** * Chromium's binary-framed protocol that includes header compression, multiplexing multiple * requests on the same socket, and server-push. HTTP/1.1 semantics are layered on SPDY/3. * * <p>This version of OkHttp implements SPDY 3 <a * href="http://dev.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3-1">draft 3.1</a>. Future * releases of OkHttp may use this identifier for a newer draft of the SPDY spec. */ SPDY_3("spdy/3.1"), /** * The IETF's binary-framed protocol that includes header compression, multiplexing multiple * requests on the same socket, and server-push. HTTP/1.1 semantics are layered on HTTP/2. * * <p>HTTP/2 requires deployments of HTTP/2 that use TLS 1.2 support {@linkplain * CipherSuite#TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256} , present in Java 8+ and Android 5+. Servers * that enforce this may send an exception message including the string {@code * INADEQUATE_SECURITY}. */ HTTP_2("h2"); }接着看
OkHttpClient.newCall(request);
Call类是一个准备执行的请求,它可以被取消,它代表着一个单一的请求/响应流,不能被执行两次。Call类是一个抽象类,
public interface Call { /** Returns the original request that initiated this call. */ Request request(); /** * Invokes the request immediately, and blocks until the response can be processed or is in * error. * * <p>The caller may read the response body with the response's {@link Response#body} method. To * avoid leaking resources callers must {@linkplain ResponseBody close the response body}. * * <p>Note that transport-layer success (receiving a HTTP response code, headers and body) does * not necessarily indicate application-layer success: {@code response} may still indicate an * unhappy HTTP response code like 404 or 500. * * @throws IOException if the request could not be executed due to cancellation, a connectivity * problem or timeout. Because networks can fail during an exchange, it is possible that the * remote server accepted the request before the failure. * @throws IllegalStateException when the call has already been executed. */ Response execute() throws IOException; /** * Schedules the request to be executed at some point in the future. * * <p>The {@link OkHttpClient#dispatcher dispatcher} defines when the request will run: usually * immediately unless there are several other requests currently being executed. * * <p>This client will later call back {@code responseCallback} with either an HTTP response or a * failure exception. * * @throws IllegalStateException when the call has already been executed. */ void enqueue(Callback responseCallback); /** Cancels the request, if possible. Requests that are already complete cannot be canceled. */ void cancel(); /** * Returns true if this call has been either {@linkplain #execute() executed} or {@linkplain * #enqueue(Callback) enqueued}. It is an error to execute a call more than once. */ boolean isExecuted(); boolean isCanceled(); interface Factory { Call newCall(Request request); }}newCall()方法是创建一个Call对象,
@Override public Call newCall(Request request) { return new RealCall(this, request); }RealCall类继承自Call类,下面展示RealCall()方法的代码,
protected RealCall(OkHttpClient client, Request originalRequest) { this.client = client; this.originalRequest = originalRequest; this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client); }
接着是RealCall的execute()方法。execute()方法是同步方法,即一直等待http请求, 直到返回了响应. 在这之间会阻塞进程, 所以通过同步方法不能在Android的主线程中执行, 否则会报错。
OKHttp提供了execute()方法(同步方法)和enqueue()方法(异步方法),下面我们先看看execute()方法(同步方法),
@Override public Response execute() throws IOException { synchronized (this) { if (executed) throw new IllegalStateException("Already Executed"); executed = true; } try { client.dispatcher().executed(this); Response result = getResponseWithInterceptorChain(); if (result == null) throw new IOException("Canceled"); return result; } finally { client.dispatcher().finished(this); } }
execute()方法,首先判断是否已执行过,如果已经执行过,则抛出异常信息,也就是说一次Call实例只能调用一次execute()方法,和我们之前说的一样。
如果未执行,则调用Dispatcher类的executed()方法将该Call加入到一个双端队列中,
... private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();//双端队列 ... /** Used by {@code Call#execute} to signal it is in-flight. */ synchronized void executed(RealCall call) { runningSyncCalls.add(call); }
接着调用getResponseWithInterceptorChain()方法返回Response对象,最后finally中,调用Dispatcher的finished()方法,在从已经执行的双端队列中移除本次Call。
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(); } }
通过上面分析,真正发出网络请求,返回结果应该是getResponseWithInterceptorChain()方法,那么接下来,主要看看这个方法
private 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 (!retryAndFollowUpInterceptor.isForWebSocket()) { interceptors.addAll(client.networkInterceptors()); } interceptors.add(new CallServerInterceptor( retryAndFollowUpInterceptor.isForWebSocket())); Interceptor.Chain chain = new RealInterceptorChain( interceptors, null, null, null, 0, originalRequest); return chain.proceed(originalRequest); }仔细查看便会发现,该方法是组装各种拦截器为一个拦截器链,最后调用RealInterceptorChain的proceed()方法,来处理这个请求,
@Override public Response proceed(Request request) throws IOException { return proceed(request, streamAllocation, httpStream, connection); } public Response proceed(Request request, StreamAllocation streamAllocation, HttpStream httpStream, Connection connection) throws IOException { if (index >= interceptors.size()) throw new AssertionError(); calls++; // If we already have a stream, confirm that the incoming request will use it. if (this.httpStream != null && !sameConnection(request.url())) { throw new IllegalStateException("network interceptor " + interceptors.get(index - 1) + " must retain the same host and port"); } // If we already have a stream, confirm that this is the only call to chain.proceed(). if (this.httpStream != null && calls > 1) { throw new IllegalStateException("network interceptor " + interceptors.get(index - 1) + " must call proceed() exactly once"); } // Call the next interceptor in the chain. RealInterceptorChain next = new RealInterceptorChain( interceptors, streamAllocation, httpStream, connection, index + 1, request); Interceptor interceptor = interceptors.get(index); Response response = interceptor.intercept(next); // Confirm that the next interceptor made its required call to chain.proceed(). if (httpStream != null && index + 1 < interceptors.size() && next.calls != 1) { throw new IllegalStateException("network interceptor " + interceptor + " must call proceed() exactly once"); } // Confirm that the intercepted response isn't null. if (response == null) { throw new NullPointerException("interceptor " + interceptor + " returned null"); } return response; }拦截器Interceptor和拦截器链Chain都是接口,
public interface Interceptor { Response intercept(Chain chain) throws IOException; interface Chain { Request request(); Response proceed(Request request) throws IOException; Connection connection(); }}
下面用一张流程图来说明拦截器链递归从拦截器中返回Response(这个过程很类似Android中的事件处理机制)
下面再看看enqueue()方法(异步方法),指在另外的工作线程中执行http请求, 请求时不会阻塞当前的线程, 所以可以在Android主线程中使用。
@Override public void enqueue(Callback responseCallback) { synchronized (this) { if (executed) throw new IllegalStateException("Already Executed"); executed = true; } client.dispatcher().enqueue(new AsyncCall(responseCallback)); }该方法和同步方法一样,首先都校验这个Call是否已经被执行,如果执行过,就报异常。如果为执行,则调用Dispatcher分发器的enqueue()方法。首先,我们看看AsyncCall这个类,
final class AsyncCall extends NamedRunnable { private final Callback responseCallback; private AsyncCall(Callback responseCallback) { super("OkHttp %s", redactedUrl().toString()); 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 { responseCallback.onFailure(RealCall.this, e); } } finally { client.dispatcher().finished(this); } } }
public abstract class NamedRunnable implements Runnable { protected final String name; public NamedRunnable(String format, Object... args) { this.name = Util.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–实际上是一个Runnable,在run()方法中调用了execute()方法,在该方法中,我们又看到既熟悉又陌生的代码(getResponseWithInterceptorChain()),
Response response = getResponseWithInterceptorChain();执行该方法后,根据响应结果设置回调方法的结果。AsyncCall执行完调用Dispatcher的finished(this)方法,
void finished(AsyncCall call) { finished(runningAsyncCalls, call, true); } 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(); } }finished()方法先从runningAsyncCalls(异步请求队列)删除已经执行的异步请求,然后接着调用了promoteCalls()方法,
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. } }首先判断runningAsyncCalls(异步请求队列)是否还有请求,如果有,则返回;否则readyAsyncCalls(异步调用准备任务)是否为空,如果为空,则返回;否则,循环readyAsyncCalls(异步调用准备任务),将call加入到runningAsyncCalls(异步请求队列)中,并在readyAsyncCalls(异步调用准备任务)删除掉该call,接着线程池执行call。
下面接着看Dispatcher分发器的enqueue()方法,
synchronized void enqueue(AsyncCall call) { if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) { runningAsyncCalls.add(call); executorService().execute(call); } else { readyAsyncCalls.add(call); } }如果runningAsyncCalls的大小小于最大请求数量(最大线程数量、并发数量)并且call小于最大主机请求限制,那么将call 加入到runningAsyncCalls中,接着线程池执行call;否则,将call加入到readyAsyncCalls(异步调用准备任务)。
PS: runningCallsForHost()方法,循环判断cal的hostl和runningAsyncCalls的中的call的host相同的数量。同一请求是否超过想过请求同时存在的最大值。
private int runningCallsForHost(AsyncCall call) { int result = 0; for (AsyncCall c : runningAsyncCalls) { if (c.host().equals(call.host())) result++; } return result; }
可以看到请求的最核心代码,与Dispatcher类分不开,下面就看看Dispatcher类,Dispatcher是异步请求的策略,
public final class Dispatcher { private int maxRequests = 64; private int maxRequestsPerHost = 5; private Runnable idleCallback; /** Executes calls. Created lazily. */ private ExecutorService executorService; /** 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<>(); /** Running synchronous calls. Includes canceled calls that haven't finished yet. */ private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>(); ...}Dispatcher维护了如下变量,
int maxRequests = 64: 最大并发请求数为64
int maxRequestsPerHost = 5: 每个主机最大请求数为5
Runnable idleCallback:Runnable对象,在删除任务时执行
ExecutorService executorService:消费者池(也就是线程池)
Deque<AsyncCall> readyAsyncCalls:缓存,异步调用准备执行任务
Deque<AsyncCall> runningAsyncCalls:正在运行的异步任务,包含取消尚未完成的调用
Deque<RealCall> runningSyncCalls: 正在运行的同步任务,包含取消尚未完成的调用
至此,OKHttp的源码分析就结束了!希望本篇文章对读者有所收获!
下面结合本篇文章,总结OKHttp的整体流程,流程图如下所示,
- Android OkHttp(三)源码解析
- OKHttp源码解析(三)
- OKHttp源码解析(三)
- OKHttp源码解析(三)
- Android OKHttp 源码解析
- Android OKHttp源码解析
- OkHttp完全解析(十)源码解析三
- 安卓面试清单----OKHttp源码解析(三)
- OKHttp源码解析(一)
- OKHttp源码解析(二)
- OKHttp源码解析(二)
- OKHttp源码解析(二)
- OKHttp源码解析(一)
- OKHttp源码解析(一)
- OkHttp源码解析(1)
- okhttp源码解析(2)
- okhttp源码解析(3)
- OKHttp源码解析(一)
- Python实现mysql数据输出到word表格中(源码)
- UGUI--背包系统之一-------InventoryManager
- 查询 数据平均值 和重复记录
- JavaScript中的函数参数详解
- apex:actionRegion
- Android OkHttp(三)源码解析
- React Native 学习笔记十八(关于样式 补充)
- Unity 3D涂色
- 深度学习中的数学与技巧(11):dropout原理解读
- 如何通过JS调用某段SQL语句
- python(十一)上:RabbitMQ 使用详细介绍
- liinx下 安装phpstudy
- pthon--字符串拼接
- 初级dba阅读书籍