赞
踩
- val client = OkHttpClient()
- val request = Request.Builder()
- .url("https://www.baidu.com")
- .build()
- val response = client.newCall(request).execute().body().toString()
注意:发送请求后,就会进入阻塞状态,直到收到响应。
- val client = OkHttpClient()
- val request = Request.Builder()
- .url("https://www.baidu.com")
- .build()
- val response = client.newCall(request).enqueue(object: Callback {
- override fun onFailure(call: Call, e: IOException) {
- TODO("Not yet implemented")
- }
- override fun onResponse(call: Call, response: Response) {
- response.body().toString()
- }
- })
注意:下面的源代码段可能来自不同一个类文件,只是将他们放一起,容易观察,主要放一些关键代码,其他会有...代替。
- public OkHttpClient() {
- this(new Builder());
- }
-
- public Builder() {
- dispatcher = new Dispatcher();
- protocols = DEFAULT_PROTOCOLS;
- connectionSpecs = DEFAULT_CONNECTION_SPECS;
- ......
- connectionPool = new ConnectionPool();
- .....
- }
可以看到OkHttp采用了建造者模式,在Builder()里面封装各种需要的属性,关键的主要有dispatcher分发器,connectionSpecs决定是异步还是同步,connectionPool 连接池。连接池具体到连接拦截器才会使用到,每个连接都会放入连接池中,由它进行管理。
总结:新建Client对象时,新建了一个分发器和一个连接池,还有一些属性的初始化。
- public Builder() {
- this.method = "GET";
- this.headers = new Headers.Builder();
- }
-
- 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);
- }
可以看到Request里面也有一个Builder类,Builder构造函数默认请求方式为Get,还有对请求头部的封装。
总结:新建一个Request对象里面主要封装了请求路径,头部信息等。
- @Override public Call newCall(Request request) {
- return RealCall.newRealCall(this, request, false /* for web socket */);
- }
-
- //可以看到newCall方法里面是调用了RealCall类的newRealCall方法,下面到RealCall类里看看。
-
- static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
- // 调用RealCall的构造函数
- RealCall call = new RealCall(client, originalRequest, forWebSocket);
- call.eventListener = client.eventListenerFactory().create(call);
- return call;
- }
-
- //下面是RealCall类构造函数
-
- private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
- this.client = client;
- this.originalRequest = originalRequest;
- this.forWebSocket = forWebSocket;
- this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
- ......
- }
总结:newCall方法实际生成RealCall对象,对象里面包含了Client客户对象和Request的请求对象,还新建了一个RetryAndFollowUpInterceptor 重定向拦截器。
- @Override public Response execute() throws IOException {
- .....
- //开启事件监听
- eventListener.callStart(this);
- try {
- //分发器用executed方法将Call对象添加进同步运行队列
- client.dispatcher().executed(this);
- //结果是从拦截器链方法中获取的
- Response result = getResponseWithInterceptorChain();
- ......
- } finally {
- //finish方法里将Call对象从Calls队列中移出
- client.dispatcher().finished(this);
- }
- }
-
- //下面进到client.dispatcher().executed(this)的excuted方法里面
-
- synchronized void executed(RealCall call) {
- //runningSyncCalls是正在运行的同步队列
- runningSyncCalls.add(call);
- }
-
总结:excute()同步申请方法,分发器将Call对象添加到同步运行队列。请求数据从Response result = getResponseWithInterceptorChain(); 中获取。
- @Override public void enqueue(Callback responseCallback) {
- //判断是否请求过这个Call对象
- synchronized (this) {
- if (executed) throw new IllegalStateException("Already Executed");
- executed = true;
- }
- //异常检测
- captureCallStackTrace();
- //事件监听
- eventListener.callStart(this);
- //调用分发器的enqueue方法,分发器在client创建时新建的。
- client.dispatcher().enqueue(new AsyncCall(responseCallback));
- }
可以看到enqueue方法里面又调用了分发器的enqueue方法,在enqueue方法里新建了一个AsyncCall对象,
AsyncCall对象传入我们上一层传入enqueue方法的CallBack对象。
接下来看看上面的AsyncCall类是什么东西。
- final class AsyncCall extends NamedRunnable {
- private final Callback responseCallback;
-
- AsyncCall(Callback responseCallback) {
- super("OkHttp %s", redactedUrl());
- this.responseCallback = responseCallback;
- }
- ...........
- }
看到AsyncCall继承自NamedRunnable,再来看看NamedRunnable是什么东西
- public abstract class NamedRunnable implements Runnable {
- .....
- @Override public final void run() {
- String oldName = Thread.currentThread().getName();
- Thread.currentThread().setName(name);
- try {
- execute();
- } finally {
- Thread.currentThread().setName(oldName);
- }
- }
- .....
- }
可以看到NamedRunnable实现了Runnable接口,里面最核心的就是在run方法里面运行了execute()方法,这个方法的具体实现其实跟同步请求execute方法一样,在AsyncCall类里,和同步请求最后的execute()是同一个方法。
- @Override protected void execute() {
- .......
- Response response = getResponseWithInterceptorChain();
- .....
- }
我把大部分代码都省了,最重要的就上面那句,跟同步请求一样,最后结果也是经过一系列拦截器的方法后的数据。
那么同步跟异步有什么区别呢?
异步传入enqueue方法的CallBack的对象实现了Runnable接口,让它在子线程中运行。
还有,接下来回到开头看看client.dispatcher().enqueue(new AsyncCall(responseCallback));这句,分发器类里的变量和它的enqueue方法(刚刚看的是AsyncCall类)。
- public final class Dispatcher {
- //默认的最大并发请求量
- private int maxRequests = 64;
- //单个host支持的最大并发量
- private int maxRequestsPerHost = 5;
- .........
- //异步等待队列
- private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
-
- //异步运行队列
- private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
-
- //同步运行队列
- private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
- ...........
- //计算队列内请求数量的方法,如果异步请求满足不超过64,5的条件则进行请求操作。
- //有的版本OkHttp是通过promoteAndExecute()进行条件判断,原理差不多
- synchronized void enqueue(AsyncCall call) {
- if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
- //把Call对象添加进runningAsyncCalls异步进行队列
- runningAsyncCalls.add(call);
- //创建线程池并执行Call请求
- executorService().execute(call);
- } else {
- readyAsyncCalls.add(call);
- }
- }
- ......
- }
分发器对Request类型进行判断,把Call对象添加进readyAsyncCalls异步等待队列或runningAsyncCalls,而在同步请求时分发器是把Call对象直接添加到runningSyncCalls同步运行队列。异步请求最后开启线程池获取数据。
总结:enqueue方法传入CallBack对象,CallBack对象被封装为AsyncCall,AsyncCall内部实现了Runnable接口,分发器进行判断,如果符合条件就把AsyncCall传入了异步进行对列,开启线程池在子线程获取数据。否则添加进异步等待队列。
我们已经知道异步跟同步请求通过分发器分发队列,但是最后都要经过AsyncCall类的execute()方法来获取数据,execute()方法最后finally里面运行client.dispatcher().finished(this);方法,我们进去finished方法看看。
- //异步请求的finished方法
- void finished(AsyncCall call) {
- finished(runningAsyncCalls, call, true);
- }
- //同步请求的finished方法
- void finished(RealCall call) {
- finished(runningSyncCalls, call, false);
- }
- //具体的finished方法
- 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!");
- //注意promoteCalls是第三个参数,既如果是异步请求才会运行该方法,重新整理队列。
- if (promoteCalls) promoteCalls();
- runningCallsCount = runningCallsCount();
- idleCallback = this.idleCallback;
- }
- if (runningCallsCount == 0 && idleCallback != null) {
- idleCallback.run();
- }
- }
进入promoteCalls()方法
- private void promoteCalls() {
- if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
- if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
- //循环到队列最后一个元素,call为最后一个请求
- for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
- AsyncCall call = i.next();
- //如果符合条件就把call从等待队列移除加入运行队列。
- if (runningCallsForHost(call) < maxRequestsPerHost) {
- i.remove();
- runningAsyncCalls.add(call);
- executorService().execute(call);
- }
- if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
- }
- }
总结:在readyAsyncCalls队列中的请求会在异步请求的finished方法里进行判断,如果符合条件则进入runningAsyncCalls。
从上面的Dispatcher类可以看出分发器有3个队列,异步有两个队列是运用了消费者模式,类中还有excuted,enqueue,finished方法,Dispatcher主要作用就是根据Request类型将Call对象调入不同队列,最后用finished将完成的请求移除队列并把等待的请求调进运行队列。
下面进到executorService().execute(call)看看,
- 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;
- }
第一个参数代表核心线程数量,为0就代表线程空闲之后不会被保留,会被销毁;如果大于0,即使本地任务执行完毕,核心线程也不会被销毁。
第二个参数是int整数的最大值,他表示的是线程池中可以容纳的最大线程数量。但是确实它得满足64跟5的条件。
第三个keepAliveTime,当我们的线程池中线程数量大于核心线程数量时,空闲线程需要等待60秒的时间才会被终止。
我们已经知道了请求最后都是从Response result = getResponseWithInterceptorChain()这句中获取的数据。
- 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 (!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);
- }
总归创建了6个拦截器
负责失败重连的拦截器。
该拦截器是链接客户端代码和网络代码的桥梁,它首先将客户端构建的Request对象信息构建成真正的网络请求;然后发起网络请求,最后就是讲服务器返回的消息封装成一个Response对象。
该拦截器用于处理缓存的功能,主要取得缓存 response 返回并刷新缓存。
该拦截器的功能就是负责与服务器建立 Socket 连接,并且创建了一个 HttpCodec它包括通向服务器的输入流和输出流。
该拦截器的功能使用 HttpCodec与服务器进行数据的读写操作的。
当然它也有缺点:
OkHttp中所有的连接(RealConnection)都是通过ConnectionPool来管理。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。