Okhttp3源码浅析
来源:互联网 发布:中美打击网络犯罪 编辑:程序博客网 时间:2024/06/13 09:57
Okhttp3出来很久了,自己也用了一段时间了,之前一直都是生搬硬套的造轮子,今天根据网上的学习资料加上自己看了源码,把自己理解的部分记录下来。
OKhttp3特点
1.支持HTTP2/SADY
2.Socket选择最好的路线,并支持自动重连
3.拥有自动维护的Socket线程池,减少握手次数。
4.拥有队列线程池,轻松写并发
5.使用Interceptor处理请求响应(比如透明GZIP压缩)
6.基于Headers缓存策略
从网络请求入手
OkhttpClient.build 初始化
public OkHttpClient build() { return new OkHttpClient(this); }
OkhttpClient.newCall 其实是OkhttpClient实现了Call.Factory接口,
public class OkHttpClient implements Cloneable, Call.Factory {
Call.Factory接口里面的newCall 方法实现
interface Factory { Call newCall(Request request); }
通过newCall又创建了一个新的Call , 而这个Call 是通过new RealCall来赋值的
@Override public Call newCall(Request request) { return new RealCall(this, request); }
RealCall 持有封装好的OkhttpClient,Requst,ps这里RetryAndFollowUpInterceptor先不做分析
protected RealCall(OkHttpClient client, Request originalRequest) { this.client = client; this.originalRequest = originalRequest; this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client); }
同步请求
OkhttpClient.newCall().excute() 这个 newCall().excute() = new RealCall().excute 因为newCall 是通过 new RealCall 来赋值的
@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); } }
这段代码说明几个问题
1.判断这个RealCall是否已经执行,Call只能被执行一次 否则就报IllegalStateExcption
if (executed) throw new IllegalStateException("Already Executed"); executed = true; }
2.把创建好的RealClaa交给线程池来执行
client.dispatcher().executed(this);
3.通过getResponseWithInterceptorChain()获得返回结果Response
Response result = getResponseWithInterceptorChain();
4.最后还要通知dispatch执行完毕
client.dispatcher().finished(this);
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<>(); //正在执行的同步请求,包含已经取消单未执行完的请求
ExecutorService初始化配置
public synchronized ExecutorService executorService() { if (executorService == null) { executorService = new ThreadPoolExecutor(0,//并发线程数如果为0,空闲一段时间销毁所有线程 Integer.MAX_VALUE, //并发线程数最大值 60, //当线程数大于并发线程的时候 TimeUnit.SECONDS,//多余空闲线程的最大存活时间 new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false)); } return executorService; }
然后在继续分析ResponseWithInterceptorChain()
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());//配置OkhttpClient,设置newworkInterceptors } interceptors.add(new CallServerInterceptor(//负责想服务器发送请求,从服务器读取请求 retryAndFollowUpInterceptor.isForWebSocket())); Interceptor.Chain chain = new RealInterceptorChain( interceptors, null, null, null, 0, originalRequest); return chain.proceed(originalRequest); }
既然是网络请求 就先从ConnctInterceptor开始,建立了一个HttpStream 分别对应Http1Code.http2Code(HTTP1.1/HTTP2)
@Override public Response intercept(Chain chain) throws IOException { RealInterceptorChain realChain = (RealInterceptorChain) chain; Request request = realChain.request(); StreamAllocation streamAllocation = realChain.streamAllocation(); // We need the network to satisfy this request. Possibly for validating a conditional GET. boolean doExtensiveHealthChecks = !request.method().equals("GET"); HttpStream httpStream = streamAllocation.newStream(client, doExtensiveHealthChecks); RealConnection connection = streamAllocation.connection(); return realChain.proceed(request, streamAllocation, httpStream, connection); }
发送数据和接收数据CallSeverInterceptor
@Override public Response intercept(Chain chain) throws IOException { HttpStream httpStream = ((RealInterceptorChain) chain).httpStream(); StreamAllocation streamAllocation = ((RealInterceptorChain) chain).streamAllocation(); Request request = chain.request(); long sentRequestMillis = System.currentTimeMillis(); httpStream.writeRequestHeaders(request); if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) { Sink requestBodyOut = httpStream.createRequestBody(request, request.body().contentLength()); BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut); request.body().writeTo(bufferedRequestBody); bufferedRequestBody.close(); } httpStream.finishRequest(); Response response = httpStream.readResponseHeaders() .request(request) .handshake(streamAllocation.connection().handshake()) .sentRequestAtMillis(sentRequestMillis) .receivedResponseAtMillis(System.currentTimeMillis()) .build(); if (!forWebSocket || response.code() != 101) { response = response.newBuilder() .body(httpStream.openResponseBody(response)) .build(); } if ("close".equalsIgnoreCase(response.request().header("Connection")) || "close".equalsIgnoreCase(response.header("Connection"))) { streamAllocation.noNewStreams(); } int code = response.code(); if ((code == 204 || code == 205) && response.body().contentLength() > 0) { throw new ProtocolException( "HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength()); } return response; }
1。向服务器发送了Request Header
2.如果有Request body,就向服务器发送
3.读取Response body,构造一个Response
4.如果有Response body 就在3的基础上增加一个新的Response
回到new RealCall.excute第四个问题 通知dispatch执行完毕
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(); } }
这段代码调用了一个promoteCalls()方法 把队列中的AsyncCall 变成runnigAsyncCall 异步
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. } }
同步请求就分析到这里 , 下面看 异步请求
OkhttpClient.newCall()。equeue() 还是同样的道理 newClaa,equeue = new RealCall().equeue
@Override public void enqueue(Callback responseCallback) { synchronized (this) { if (executed) throw new IllegalStateException("Already Executed"); executed = true; } client.dispatcher().enqueue(new AsyncCall(responseCallback)); }
client.dispatcher().equeue(new AsyncCall(responseCalllback));
synchronized void enqueue(AsyncCall call) { if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) { runningAsyncCalls.add(call); executorService().execute(call); } else { readyAsyncCalls.add(call); } }
如果disparch线程池还能执行并发请求,那么就立即执行,否则加入readAsyncCall 然后执行完毕会执行promoteCalls() 把readAsyncCall变成异步请求
最后放一张 流程图
阅读全文
0 0
- Okhttp3源码浅析
- 浅析 - okHttp3使用总结
- OkHttp3源码分析
- OkHttp3源码分析[综述]
- OkHttp3 源码解读
- OkHttp3源码学习简要
- okHttp3源码简要分析
- okhttp3 源码深入分析
- 源码阅读--OkHttp3
- Okhttp3源码解析
- OkHttp3源码分析[综述]
- OkHttp3源码分析[DiskLruCache]
- OkHttp3 源码解读
- OkHttp3源码解析
- okhttp3 源码分析
- 关于OkHttp3源码分析
- OkHttp3源码解析
- OkHttp3源码分析[缓存策略]
- XMLHttpRequest对象的属性和方法
- 关于java中的值传递与引用传递的见解
- 3、Node.js => 函数
- poj 1979 dfs
- UML类图
- Okhttp3源码浅析
- 原生JS字符串拼接实例
- 笔记-SimHash
- java中异常
- js的继承问题
- BigDecimal
- ccf 201512-4 送货 无向图欧拉回路
- Struts2拦截器-学习篇三
- 7z lzma920源码封装 C++ DLL,可直接调用压缩