OkHttp官網地址:https://square.github.io/okhttp/java
用法以下:(get請求)git
package okhttp3.guide; import java.io.IOException; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; public class GetExample { OkHttpClient client = new OkHttpClient(); String run(String url) throws IOException { Request request = new Request.Builder() .url(url) .build(); try (Response response = client.newCall(request).execute()) { return response.body().string(); } } public static void main(String[] args) throws IOException { GetExample example = new GetExample(); String response = example.run("https://raw.github.com/square/okhttp/master/README.md"); System.out.println(response); } }
Github下載源碼地址https://github.com/square/okhttpgithub
4.x以上的版本都大部分更新爲kotlin了,能夠更改分支下載3.x的版原本看web
一。先來看第一步構造函數緩存
OkHttpClient client = new OkHttpClient();
源碼:微信
public OkHttpClient() { this(new Builder()); }
Builder()中就是初始化了一堆變量,沒啥東西cookie
二。來看get請求socket
new Request.Builder()
源碼:找內部類Builder的構造函數ide
public Builder() { this.method = "GET"; this.headers = new Headers.Builder(); }
源碼:接着找Headers的內部類Builder,暫時構造了一個變量,尚未作什麼函數
三。下面是執行.url方法,固然是Request內部類Builder的url方法,url暫定爲String
源碼:
public Builder url(String url) { if (url == null) throw new NullPointerException("url == null"); // Silently replace web socket 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); } return url(HttpUrl.get(url)); }
前面是加前綴,後面去到HttpUrl裏去
public static HttpUrl get(String url) { return new Builder().parse(null, url).build(); }
HttpUrl的內部類Builder的構造函數
public Builder() { encodedPathSegments.add(""); // The default path is '/' which needs a trailing space. }
encodedPathSegments是一個ArrayList
HttpUrl的內部類Builder的parse方法就是一連串的參數解析,你們能夠看源碼
最後一個build()方法
public HttpUrl build() { if (scheme == null) throw new IllegalStateException("scheme == null"); if (host == null) throw new IllegalStateException("host == null"); return new HttpUrl(this); }
這個HttpUrl的帶參構造函數中也是一堆變量的初始化
回到Request內部類Builder的url方法
public Builder url(HttpUrl url) { if (url == null) throw new NullPointerException("url == null"); this.url = url; return this; }
接着是Request內部類Builder的build方法
public Request build() { if (url == null) throw new IllegalStateException("url == null"); return new Request(this); }
Request的帶參構造函數
Request(Builder builder) { this.url = builder.url; this.method = builder.method; this.headers = builder.headers.build(); this.body = builder.body; this.tags = Util.immutableMap(builder.tags); }
四。接下來很重要了,是執行請求
Response response = client.newCall(request).execute()
OkHttpClient中的newCall方法
@Override public Call newCall(Request request) { return RealCall.newRealCall(this, request, false /* for web socket */); }
進到RealCall中的newRealCall方法
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.transmitter = new Transmitter(client, call); return call; }
構造函數不用管,進去Transmitter中的構造函數
public Transmitter(OkHttpClient client, Call call) { this.client = client; this.connectionPool = Internal.instance.realConnectionPool(client.connectionPool()); this.call = call; this.eventListener = client.eventListenerFactory().create(call); this.timeout.timeout(client.callTimeoutMillis(), MILLISECONDS); }
其中這個Internal.instance.realConnectionPool(client.connectionPool())能夠找到OkHttpClient的static代碼塊執行後返回了一個RealConnectionPool
private static final Executor executor = new ThreadPoolExecutor(0 /* corePoolSize */, Integer.MAX_VALUE /* maximumPoolSize */, 60L /* keepAliveTime */, TimeUnit.SECONDS, new SynchronousQueue<>(), Util.threadFactory("OkHttp ConnectionPool", true));
RealConnectionPool一看就知道是0個核心線程,最大值個非核心線程的線程池;這裏還出現了一個Deque雙端隊列,即隊列的升級版,兩個端口均可以進出元素,更加靈活
最後就是RealCall的execute方法了,注意RealCall裏有個內部類AsyncCall也有execute方法,注意不要搞混了
@Override public Response execute() throws IOException { synchronized (this) { if (executed) throw new IllegalStateException("Already Executed"); executed = true; } transmitter.timeoutEnter(); transmitter.callStart(); try { client.dispatcher().executed(this); return getResponseWithInterceptorChain(); } finally { client.dispatcher().finished(this); } }
client.dispatcher().executed(this)執行的是
synchronized void executed(RealCall call) { runningSyncCalls.add(call); }
runningSyncCalls就是咱們上面提到的Deque雙端隊列
下面就是最最核心的getResponseWithInterceptorChain方法
Response getResponseWithInterceptorChain() throws IOException { // Build a full stack of interceptors. List<Interceptor> interceptors = new ArrayList<>(); interceptors.addAll(client.interceptors()); interceptors.add(new RetryAndFollowUpInterceptor(client)); 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, transmitter, null, 0, originalRequest, this, client.connectTimeoutMillis(), client.readTimeoutMillis(), client.writeTimeoutMillis()); boolean calledNoMoreExchanges = false; try { Response response = chain.proceed(originalRequest); if (transmitter.isCanceled()) { closeQuietly(response); throw new IOException("Canceled"); } return response; } catch (IOException e) { calledNoMoreExchanges = true; throw transmitter.noMoreExchanges(e); } finally { if (!calledNoMoreExchanges) { transmitter.noMoreExchanges(null); } } }
RetryAndFollowUpInterceptor重試和跳轉攔截器
BridgeInterceptor橋接攔截器,即加請求頭和去響應頭
CacheInterceptor緩存攔截器
ConnectInterceptor鏈接攔截器
CallServerInterceptor調用服務攔截器
List添加好所有Interceptor以後,執行chain.proceed(originalRequest)來到RealInterceptorChain中的proceed方法
public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange) 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.exchange != null && !this.exchange.connection().supportsUrl(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.exchange != 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, transmitter, exchange, index + 1, request, call, connectTimeout, readTimeout, writeTimeout); Interceptor interceptor = interceptors.get(index); Response response = interceptor.intercept(next); // Confirm that the next interceptor made its required call to chain.proceed(). if (exchange != 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"); } if (response.body() == null) { throw new IllegalStateException( "interceptor " + interceptor + " returned a response with no body"); } return response; }
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
一開始傳入的index爲0,就是從第一個攔截器開始執行每一個攔截器的intercept方法,index逐次+1
每一個攔截器裏都調用chain.proceed,這樣全部的攔截器就造成鏈條。這裏每一個攔截器的做用就不講了
歡迎關注個人微信公衆號:安卓圈