OkHttp源码解析(小白必看,建议收藏,软件需求分析的任务

相应代码如下

//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 {

}

});

3.源码解析


看源码的流程(思想):

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();

}

}

7.最后看看promoteCalls()方法;

private void promoteCalls() {

if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.

if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.

for (Iterator 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.

}

}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数同学面临毕业设计项目选题时,很多人都会感到无从下手,尤其是对于计算机专业的学生来说,选择一个合适的题目尤为重要。因为毕业设计不仅是我们在大学四年学习的一个总结,更是展示自己能力的重要机会。

因此收集整理了一份《2024年计算机毕业设计项目大全》,初衷也很简单,就是希望能够帮助提高效率,同时减轻大家的负担。
img
img
img

既有Java、Web、PHP、也有C、小程序、Python等项目供你选择,真正体系化!

由于项目比较多,这里只是将部分目录截图出来,每个节点里面都包含素材文档、项目源码、讲解视频

如果你觉得这些内容对你有帮助,可以添加VX:vip1024c (备注项目大全获取)
img

对于计算机专业的学生来说,选择一个合适的题目尤为重要。因为毕业设计不仅是我们在大学四年学习的一个总结,更是展示自己能力的重要机会。**

因此收集整理了一份《2024年计算机毕业设计项目大全》,初衷也很简单,就是希望能够帮助提高效率,同时减轻大家的负担。
[外链图片转存中…(img-rzRwXibY-1712529550115)]
[外链图片转存中…(img-AoehK9Ah-1712529550116)]
[外链图片转存中…(img-0a4qNPhZ-1712529550116)]

既有Java、Web、PHP、也有C、小程序、Python等项目供你选择,真正体系化!

由于项目比较多,这里只是将部分目录截图出来,每个节点里面都包含素材文档、项目源码、讲解视频

如果你觉得这些内容对你有帮助,可以添加VX:vip1024c (备注项目大全获取)
[外链图片转存中…(img-SSyHmKGz-1712529550117)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值