-
1.先创建 OkHttpClient 实例;
-
2.构造 Request 实例,传入 url 等相关参数;
-
3.通过前两步中的实例对象构建 Call 对象;
-
4.异步请求通过 Call#enqueue(Callback) 方法来提交异步请求,同步请求通过 Call#execute() 直接 获取Reponse
相应代码如下
//1.创建⼀个 OkHttp 的实例
OkHttpClient client = new OkHttpClient.Builder().build();
//2.创建 Request
Request request = new Request.Builder().url(“http://www.jimengjia.com”).build();
//3.构建 Call 对象
Call call=okHttpClient.newCall(request);
//4.通过 Call#enqueue(Callback) 方法来提交异步请求
call.enqueue(new Callback() {
@Override
public void onFailure( Call call, IOException e) {
}
@Override
public void onResponse( Call call,Response response) throws IOException {
}
});
看源码的流程(思想):
1.从使用步骤中第四步可以看出起关键作用的是enqueue(),所以从源码中找到此方法开始分析。
代码如下:
@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));
}
2.从上述代码可以看到,创建了一个 AsyncCall 并将Callback传入后,最后交给了任务分发器 Dispatcher 来进一步处理。
client.dispatcher().enqueue(new AsyncCall(responseCallback)); 进入下一个调用dispatcher().enqueue();
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
//运行中的队列
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
//等待中的队列,可看成支线
readyAsyncCalls.add(call);
}
}
相应的对象如下:
private int maxRequests = 64;
private int maxRequestsPerHost = 5;
//可以很明显看出是添加到了runningAsyncCalls,readyAsyncCalls中
/** 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<>();
此方法的大致内容:对请求的入队做了一些限制,若正在执行的请求数量小于最大值(默认64),并且此请求所属主机的正在执行任务小于最大值(默认5),就加入正在运行的队列并通过线程池来执行该任务,否则加入准备执行队列中。
3.从上述代码可以看到,当满足条件后将进入executorService()
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;
}
这里的具体就是放到线程池里的运行了。(以下内容为拓展) ExecutorService的创建方式如下:所有线程池最终都是通过这个方法来创建的。
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue workQueue,ThreadFactory threadFactory,
RejectedExecutionHandler handler)
-
corePoolSize :核心线程数,一旦创建将不会再释放。如果创建的线程数还没有达到指定的核心线程数量,将会继续创建新的核心线程,直到达到最大核心线程数后,核心线程数将不在增加;如果没有空闲的核心线程,同时又未达到最大线程数,则将继续创建非核心线程;如果核心线程数等于最大线程数,则当核心线程都处于激活状态时,任务将被挂起,等待空闲线程来执行。
-
maximumPoolSize :最大线程数,允许创建的最大线程数量。如果最大线程数等于核心线程数,则无法创建非核心线程;如果非核心线程处于空闲时,超过设置的空闲时间,则将被回收,释放占用的资源。
-
keepAliveTime : 也就是当线程空闲时,所允许保存的最大时间,超过这个时间,线程将被释放销毁,但只针对于非核心线程。
-
unit : 时间单位,TimeUnit.SECONDS等。
-
workQueue : 任务队列,存储暂时无法执行的任务,等待空闲线程来执行任务。
-
threadFactory : 线程工程,用于创建线程。
-
handler : 当线程边界和队列容量已经达到最大时,用于处理阻塞时的程序
可以明显的看到创建时使用的队列为SynchronousQueue:它内部没有容器(可以去拓展一下,本文就不写了)
4.进入到下一个代码区execute():
@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 {
//维护,执行完之后,调用dispatcher中的finish函数
client.dispatcher().finished(this);
}
}
5.可以明显的看到处理请求的为getResponseWithInterceptorChain()方法
//责任链模式的设计
//(从一些维度来优化,如用户流量,响应速度,减少服务器承受的压力)
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);
}
这个方法里面通过拦截器组成的责任链,依次经过用户自定义普通拦截器、重试拦截器、桥接拦截器、缓存拦截器、 连接拦截器和用户自定义网络拦截器以及访问服务器拦截器等拦截处理过程来获取到一个响应并交给用户。
各个拦截器的作用:
-
interceptors:用户自定义拦截器(根据具体业务决定)
-
retryAndFollowUpInterceptor:负责失败重试以及重定向
-
BridgeInterceptor:请求时,对必要的 Header 进行一些添加,接收响应时,移除必要的 Header
-
CacheInterceptor:负责读取缓存直接返回(根据请求的信息和缓存的响应的信息来判断是否存在缓存可用)、更新缓存
-
ConnectInterceptor:负责和服务器建立连接。
6.回到第四步维护,调用dispatcher中的finish函数
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;
}
//如果队列没有在执行的线程且idle线程不为空则执行。 可以看出每个线程结束完都会检查一遍是不是
//要执行空闲线程
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
}
总结:
各行各样都会淘汰一些能力差的,不仅仅是IT这个行业,所以,不要被程序猿是吃青春饭等等这类话题所吓倒,也不要觉得,找到一份工作,就享受安逸的生活,你在安逸的同时,别人正在奋力的向前跑,这样与别人的差距也就会越来越遥远,加油,希望,我们每一个人,成为更好的自己。
-
BAT大厂面试题、独家面试工具包,
-
资料包括 数据结构、Kotlin、计算机网络、Framework源码、数据结构与算法、小程序、NDK、Flutter,
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
前跑,这样与别人的差距也就会越来越遥远,加油,希望,我们每一个人,成为更好的自己。
-
BAT大厂面试题、独家面试工具包,
-
资料包括 数据结构、Kotlin、计算机网络、Framework源码、数据结构与算法、小程序、NDK、Flutter,
[外链图片转存中…(img-obptqIjg-1714648294891)]
[外链图片转存中…(img-QwfwD9x9-1714648294892)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!