Android OKHttp源码解析
来源:互联网 发布:阿里云空间怎么买 编辑:程序博客网 时间:2024/06/01 07:27
学习了OKHttp的使用,现在来学学源码。
1、OkHttp是一个高效优秀的HTTP库
网上有很多相关的介绍文档 。
2、OKHttp的简单使用实例,实际一般都是和Retrofit结合使用,下面是OKHTTP的使用实例,分别就一二三四步进行分析:
(一) final OkHttpClient client = new OkHttpClient(); okHttpClient = new OkHttpClient.Builder() .addInterceptor() .addNetworkInterceptor() .build();(二) Request request = new Request.Builder() .url("https://www.baidu.com/") .get() .build();(三) Response response = client.newCall(request).execute(); //同步请求(四) okHttpClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Log.d(TAG,"e="+e); } @Override public void onResponse(Call call, Response response) throws IOException { Log.d(TAG,"response="+ response.body().toString()); } });
OKHttp的调用流程图:
下面来看看具体的过程:
一、OKHttpClient对象的创建
1 :创建默认设置的client,或者如上的创建:
public final OkHttpClient client = new OkHttpClient();
2: OKHttpClient通过Builder模式创建
okHttpClient = new OkHttpClient.Builder() .addInterceptor(new HttpLogginInterceptor()) .cache(new Cache(cacheDir,cacheSize)) .build();
OKHttpClient在一个应用程序中最好使用一个单例,因为每个OKHttpClient实例持有自己的线程池和连接池,重用线程池和连接池可以节省内存,如果每个请求都实例化一个client那么必然造成它本身线程池和连接池的资源浪费。当系统检测到她们已经闲置时,线程和连接资源会被自动释放,当然有需要时也可以主动释放。 * 通过Builder方式构建的OKHttpClient实例可以共享连接池、线程池和配置 * 通过client.dispatcher().executorService().shutdown():停止调度器的service,那么之后的请求都会被拒绝 * 通过client.connectionPool().evictAll():清除连接池,但是守护进程可能并不会马上释放 * 如果client有缓存的话,可以通过client.cache().close()来 关闭,但是不能重复调用,否则可能会crash * OKHttp使用了守护线程来维护HTTP/2的连接,闲置时则会自动的停止 */ 步骤1:new OKHttpClient:分析OKHttpClient的主体 步骤2:Builder() :分析Builder的构建 步骤1: OKHTTPClient的关键代码:
public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory { //Protocol是一个定义了几种协议版本http1.0,http1.1,spdy3,http2的枚举,这里返回的是装载了两个枚举常量Protocol.HTTP_2和Protocol_的不可变list static final List<Protocol> DEFAULT_PROTOCOLS = Util.immutableList( Protocol.HTTP_2, Protocol.HTTP_1_1); //ConnectionSpec:证书 static final List<ConnectionSpec> DEFAULT_CONNECTION_SPECS = Util.immutableList( ConnectionSpec.MODERN_TLS, ConnectionSpec.CLEARTEXT); /** * 静态Internal实例对象: * OKHttp3 内部一些更新的API,继承自OKHTTP的包也能够使用,这个Internal仅在OKHTTPClient中使用 * 主要通过builder来设置到client中去 */ static { Internal.instance = new Internal() { } } } //Dispatcher:执行异步请求的代理,下面有这个类的具体分析 final Dispatcher dispatcher; //网络代理,有Direct、HTTP、SOCKS三种 final Proxy proxy; //连接规范,配置Socket连接层,对于HTTPS,还能配置安全传输层协议TLS版本与密码套件(CipherSuite) final List<ConnectionSpec> connectionSpecs; //Interceptor:拦截器,观察、修改已经发出的请求或得到响应。常用来添加、移除或者转换请求或者 //response的header final List<Interceptor> interceptors; final List<Interceptor> networkInterceptors; //EventListener:请求过程监听器 final EventListener.Factory eventListenerFactory; /** * CookieJar:管理cookie,根据URL保存或者取出cookie。 * 可以自定义,有两个方法: * void saveFromResponse(HttpUrl url, List<Cookie> cookies); * List<Cookie> loadForRequest(HttpUrl url); */ final CookieJar cookieJar; //Cache :缓存HTTP和HTTPS结果到文件系统,用常见的DiskLruCache来对response进行缓存。 final Cache cache; //SocketFactory : 通过工厂方法创建Socket final SocketFactory socketFactory; final SSLSocketFactory sslSocketFactory; final CertificateChainCleaner certificateChainCleaner; //主机名验证器,与HTTPS中的SSL相关,当握手时如果URL的主机名不是可识别的主机,就会要求进行主机名验证 /** *public interface HostnameVerifier { //通过session验证指定的主机名是否被允许 boolean verify(String hostname, SSLSession session); } */ final HostnameVerifier hostnameVerifier; //证书锁,约束哪些证书可以被信任,防止某些证书机构的攻击行为,如果所有证书都不被信任将抛出 //SSLPeerUnverifiedException异常。 final CertificatePinner certificatePinner; //授权 final Authenticator proxyAuthenticator; final Authenticator authenticator; final ConnectionPool connectionPool; //DNS域名转换 final Dns dns; }
步骤2;Builder()的创建相关代码:
public Builder() { dispatcher = new Dispatcher(); //实例线程调度器 protocols = DEFAULT_PROTOCOLS; connectionSpecs = DEFAULT_CONNECTION_SPECS; eventListenerFactory = EventListener.factory(EventListener.NONE); proxySelector = ProxySelector.getDefault(); //获取系统的DefaultProxySelector cookieJar = CookieJar.NO_COOKIES; socketFactory = SocketFactory.getDefault(); connectionPool = new ConnectionPool(); //实例化一个连接池 //设置默认的连接时间,读写时间 connectTimeout = 10_000; readTimeout = 10_000; writeTimeout = 10_000; }
通过.build()生成OKHTTPClient实例,.将Builder设置的参数设置给OKHTTPClient。
Dispatcher:
/** * Dispatcher:是异步请求时的代理,所有请求都是在这里进行调用以及处理 * 每个Dispatcher使用一个ExecutorService来调用call请求。 * 如果 提供了自定义的executor,需要支持获取最大的请求数,因为Dispatcher需要根据最大值来维护请求队列 */public final class Dispatcher { //默认的最大请求并发数64 private int maxRequests = 64; //每个主机最大的请求数 private int maxRequestsPerHost = 5; //当正在运行的请求数目为0时的回调 private Runnable idleCallback; //线程池 private ExecutorService executorService; //已ready的异步请求队列 private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>(); //正在运行的异步请求队列,包括已经cancel但是还没有finish private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>(); //正在运行的同步请求队列,包括cancel但没有finish的 private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>(); //可传入自定义的线程池 public Dispatcher(ExecutorService executorService) { this.executorService = executorService; } public Dispatcher() { } //创建一个线程池实例对象 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 void setMaxRequestsPerHost(int maxRequestsPerHost) { if (maxRequestsPerHost < 1) { throw new IllegalArgumentException("max < 1: " + maxRequestsPerHost); } this.maxRequestsPerHost = maxRequestsPerHost; promoteCalls(); } //异步请求添加:如果此时运行队列大小小于最大值并且共享主机数小于最大值,则添加到正在运行队列并且将请求放入线程池执行,否则只是添加到准备队列中 synchronized void enqueue(AsyncCall call) { if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) { runningAsyncCalls.add(call); executorService().execute(call); } else { readyAsyncCalls.add(call); } } //取消所有的请求 public synchronized void cancelAll() { for (AsyncCall call : readyAsyncCalls) { call.get().cancel(); } for (AsyncCall call : runningAsyncCalls) { call.get().cancel(); } for (RealCall call : runningSyncCalls) { call.cancel(); } } //异步请求被调用的过程 private void promoteCalls() { //1、首先判断此刻运行的Call数目是否>=最大的请求数,或者没有正在等待的请求,则不需要再加载新的请求 if (runningAsyncCalls.size() >= maxRequests) return; if (readyAsyncCalls.isEmpty()) return for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) { AsyncCall call = i.next(); /** * 2、遍历即将运行的的Call,将其的host和正在运行的队列的host比较,如果共享主机数小于最大值的话 * 则将该请求添加到正在运行队列,并且从准备队列中移除 * 将该请求放入线程池执行 * 否则就继续等待。 * */ if (runningCallsForHost(call) < maxRequestsPerHost) { i.remove(); runningAsyncCalls.add(call); executorService().execute(call); } //添加的call超过了最大的值,则停止增加新的请求。 if (runningAsyncCalls.size() >= maxRequests) return; } } //返回共享主机的请求数目 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) { //将该请求call从相应的队列移除 if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!"); //移除之后再从准备队列往运行队列中添加新的请求【异步请求】 if (promoteCalls) promoteCalls(); runningCallsCount = runningCallsCount(); idleCallback = this.idleCallback; } //如果运行数目为0并且回调不为空,则调用回调的方法通知接收者请求已完成 if (runningCallsCount == 0 && idleCallback != null) { idleCallback.run(); } } //获取ready状态中的异步请求队列 public synchronized List<Call> queuedCalls() { List<Call> result = new ArrayList<>(); for (AsyncCall asyncCall : readyAsyncCalls) { result.add(asyncCall.get()); } return Collections.unmodifiableList(result); } //返回running状态中的异步请求队列 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); } //返回ready状态的异步请求数目,同步请求是马上执行的,所以没有ready这一状态 public synchronized int queuedCallsCount() { return readyAsyncCalls.size(); } //返回running状态的请求数目 public synchronized int runningCallsCount() { return runningAsyncCalls.size() + runningSyncCalls.size(); }}
二、创建一个网络请求对象Request
Request request = new Request.Builder() .url("https://www.baidu.com/") .get() .build();
来看看Request的关键代码,Request同样通过Builder模式进行创建。
//Request是请求的实体,封装了请求的URL地址、请求方法,请求头、请求参数、请求体、请求响应体等等, public final class Request { //HttpUrl封装了请求url\post等相关信息 final HttpUrl url; //OKHttp支持主流的网络请求,get/post/delete/put等方法 final String method; //定义请求头 final Headers headers; //请求体 final RequestBody body; private volatile CacheControl cacheControl; /** * 返回该响应的缓存控制指令,不为空,即使该响应没有包含Cache-Control * *头,、CacheControl是从响应header解析出来的缓存控制指令。 */ public CacheControl cacheControl() { CacheControl result = cacheControl; return result != null ? result : (cacheControl = CacheControl.parse(headers)); } //判断是否是HTTPS public boolean isHttps() { return url.isHttps(); } public static class Builder { HttpUrl url; String method; Headers.Builder headers; RequestBody body; //put 或 post、patch时定义的请求体 Object tag; public Builder() { this.method = "GET"; //默认为GET方法 this.headers = new Headers.Builder(); } //设置当前请求为下列的某种请求 public Builder get() { return method("GET", null); } public Builder head() { return method("HEAD", null); } public Builder post(RequestBody body) { return method("POST", body); } public Builder delete(RequestBody body) { return method("DELETE", body); } public Builder delete() { return delete(Util.EMPTY_REQUEST); } public Builder put(RequestBody body) { return method("PUT", body); } public Builder patch(RequestBody body) { return method("PATCH", body); } //拓展方法,可定义任意的请求方法,以及请求体 public Builder method(String method, RequestBody body) { if (method == null) throw new NullPointerException("method == null"); if (method.length() == 0) throw new IllegalArgumentException("method.length() == 0"); if (body != null && !HttpMethod.permitsRequestBody(method)) { throw new IllegalArgumentException("method " + method + " must not have a request body."); } if (body == null && HttpMethod.requiresRequestBody(method)) { throw new IllegalArgumentException("method " + method + " must have a request body."); } this.method = method; this.body = body; return this; } }}
三、通过OKHTTPClient来发起请求
先来看看同步请求: Response response = okHttpClient.newCall(request).execute(); 步骤1:看看okHttpClient.newCall(request)做了什么//1:生成一个RealCall对象@Override public Call newCall(Request request) { return new RealCall(this, request, false );}//2:RealCall对象的关键代码
//RealCall实现了Call,Call是一个定义请求的方法的接口,Request定义了请求的基本属性、设置,Call定义了请求的操作,同步、异步、取消等各项操作 final class RealCall implements Call { final OkHttpClient client; //失败重连拦截器,在下面有介绍 final RetryAndFollowUpInterceptor retryAndFollowUpInterceptor; //事件监听器,监听请求的步骤,用工厂模式创建实例对象 final EventListener eventListener; //请求对象 final Request originalRequest; // Guarded by this. private boolean executed; //创建RealCall的实例对象 RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) { final EventListener.Factory eventListenerFactory = client.eventListenerFactory(); this.client = client; this.originalRequest = originalRequest; this.forWebSocket = forWebSocket; this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket); this.eventListener = eventListenerFactory.create(this); } 步骤2:调用realCall.execute()方法执行请求,下面详细看看这个方法做了什么操作 @Override public Response execute() throws IOException { synchronized (this) { // 执行标志,不能重复执行 if (executed) throw new IllegalStateException("Already Executed"); executed = true; } try { //前面有看到,请求是由Dispatcher来调度的,所以RealCall的execute()进入到Dispatcher的executed()方法中 client.dispatcher().executed(this); //如何获取请求的返回结果的,可以看到最终的网络请求其实就是在这里做的。 Response result = getResponseWithInterceptorChain(); if (result == null) throw new IOException("Canceled"); return result; } finally { client.dispatcher().finished(this); } } 看看getResponseWithInterceptorChain()具体的实现: Response getResponseWithInterceptorChain() throws IOException { //看到这里添加了一系列的拦截器给interceptors,一个个看看这些拦截器都是做什么的 List<Interceptor> interceptors = new ArrayList<>(); interceptors.addAll(client.interceptors()); //retryAndFollowUpInterceptor:失败重连重定向拦截器 interceptors.add(retryAndFollowUpInterceptor); //BridgeInterceptor:从应用程序代码到网络代码的桥梁,将用户的request转化成网络请求,然后根据网络响应转化为用户的response。 interceptors.add(new BridgeInterceptor(client.cookieJar())); //CacheInterceptor:从缓存中发起request,并将响应写入的缓存中 interceptors.add(new CacheInterceptor(client.internalCache())); //ConnectInterceptor:打开连接到指定服务器的连接,并且传递给下一个拦截器 interceptors.add(new ConnectInterceptor(client)); if (!forWebSocket) { interceptors.addAll(client.networkInterceptors()); } //CallServerInterceptor:这是拦截器链中的最后一个拦截器,它用于对服务器发起网络请求 interceptors.add(new CallServerInterceptor(forWebSocket)); //最后将所有的拦截器传递给RealInterceptorChain对象,执行proceed()操作 Interceptor.Chain chain = new RealInterceptorChain( interceptors, null, null, null, 0, originalRequest); return chain.proceed(originalRequest); }
可以看出这是一种责任链的模式,每一个拦截器负责一项功能,完成之后往下传递。
//看看chain.proceed()做的具体内容,为了更加简明起见,把异常处理去掉
@Override public Response proceed(Request request) throws IOException { return proceed(request, streamAllocation, httpCodec, connection); } public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec, RealConnection connection) throws IOException { //index是传给RealInterceptorChain的拦截器链的索引 if (index >= interceptors.size()) throw new AssertionError(); calls++; //调用RealInterceptorChain中的下一个拦截器 RealInterceptorChain next = new RealInterceptorChain( interceptors, streamAllocation, httpCodec, connection, index + 1, request); //获取当前索引的拦截器 Interceptor interceptor = interceptors.get(index); //执行拦截器的intercept的方法,最终得到返回结果response,返回给RealCall。 Response response = interceptor.intercept(next); return response; }
以上是OKHttp请求调用的基本流程。OKHttp请求最重要的的是拦截器的作用,下面再继续看看拦截器的具体内容。
阅读全文
0 0
- Android OKHttp 源码解析
- Android OKHttp源码解析
- Android OkHttp(三)源码解析
- OKHttp源码解析
- OKHttp源码解析
- OKHttp源码解析
- OKHttp源码解析
- OKHttp源码解析
- OKHttp源码解析
- OKHttp源码解析
- OKHttp源码解析
- OKHttp源码解析
- OKHttp源码解析
- OkHttp源码解析
- OKHttp源码解析
- OKHttp源码解析
- OKHttp源码解析
- OKHttp源码解析
- 小波变换
- POJ 3304 Segments [枚举+叉乘判断线段相交]
- PTA-沙漏打印
- 地图布局相关----CSS实现div的高度填满剩余空间
- python 类的编写与调用
- Android OKHttp源码解析
- TabLayout+Fragment
- ubun_caffw_fast-rcnn编译坎坷路
- Trafodion Rename Table不成功的另外一种解决方法
- 电脑操作问题解决
- mvc框架
- Web项目文件的下载
- 算法导论-排序的Python&C++简单实现
- 安卓Debug