OkHttp源码解读

OkHttp 4是用kotlin写的,我这里使用的是3.9.1版本。

OkHttp的使用,发送同步请求

OkHttpClient client = new OkHttpClient();
// 第二步,创建请求
Request request = new Request.Builder().url("https://www.google.com").build(); // 创建GET请求
/* RequestBody body = RequestBody.create(JSON, params);
   Request request = new Request.Builder().url(url).post(body).build(); */	// 创建POST请求
// 第三步,发送请求,获取Response
Response response = client.newCall(request).execute();
/* client.newCall(request).enqueue(Callback) */		// 异步请求,callback用于接收response
复制代码

new OkHttpClient(),最重要的作用就是创建Dispatcher,这是用于分发请求是由哪个线程处理的。
new Request.Builder().url()…build(),这是建造者模式的写法,创建了请求对象,传入最重要的参数url。
第三步发送请求细,分为两步,第1步,将request包装为Call。
下面的newCall()方法的代码实例:

class OkHttpClient {
    public Call newCall(Request request) {
        return RealCall.newRealCall(this, request, false /* for web socket */);
    }
}
复制代码

上面,这个方法是OkHttpClient的方法,所以这里传入的this,是OkHttpClient本身。
第2步,调用RealCall.execute()发送请求,具体如下:

class RealCall implements Call {
public Response execute() throws IOException {
    synchronized (this) {
      	if (executed) throw new IllegalStateException("Already Executed");
      	executed = true;
    }
    transmitter.timeoutEnter();
    transmitter.callStart();
    try {
      	client.dispatcher().executed(this);
      	return getResponseWithInterceptorChain();
    } finally {
      	client.dispatcher().finished(this);
    }
}
}
复制代码

如上,client.dispatcher().executed(this),这里this是RealCall,由于RealCall封装了Request,所以可以执行行请求。// TODO,synchronized和finished都值得一讲
在构建RealCall对象时,传入了OkHttpClient对象,就是这里的client。client.dispatcher()即Dispatcher对象。
Diapathcer执行的过程,只是将请求添加到运行运行队列,如下。

class Dispatcher {
synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);
}
}
复制代码

真正发送请求,获得Response是getResponseWithInterceptorChain(),这个后面讲解(一号坑)。

使用OkHttp发送异步请求

前面的client和request创建时相同的,区别在于发送的时候,调用enqueue(),且需要传入Callback用于接收Response。
client.newCall(request).enqueue(Callback)
异步请求与同步请求类似,差异是第三步使用的enqueue()方法。下面是enqueue()的源码:

class RealCall implements Call {
    public Response execute() throws IOException {	// execute,方便与enqueue对比
	...
	client.dispatcher().executed(this);
      	return getResponseWithInterceptorChain();
    }

    public void enqueue(Callback responseCallback) {
        synchronized (this) {
            if (executed) throw new IllegalStateException("Already Executed");
                executed = true;
            }
    	transmitter.callStart();
    	client.dispatcher().enqueue(new AsyncCall(responseCallback));
    }
}
复制代码

如上,client.dispatcher().enqueue(new AsyncCall(responseCallback)),异步请求是会创建一个AsyncCall,之后再将AsyncCall入列。
下面是添加过程的源码。有一点要注意的是,AsyncCall并没有跟Request关联起来,在执行异步请求时如何拿到请求url,这里挖一个坑后面讲(二号坑)。

class Diapathcer {
    void enqueue(AsyncCall call) {
        synchronized (this) {
            readyAsyncCalls.add(call);
            if (!call.get().forWebSocket) {
                AsyncCall existingCall = findExistingCallWithHost(call.host());
                if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
            }
        }
        promoteAndExecute();
    }
}
复制代码

如上,enqueue()的执行过程,是将AsyncCall添加到异步等待队列readyAsyncCalls,然后调用promoteAndExecute(),如下是源码。

class Diapathcer {
    private boolean promoteAndExecute() {
        assert (!Thread.holdsLock(this));
        List<AsyncCall> executableCalls = new ArrayList<>();
        boolean isRunning;
        synchronized (this) {
            /* 将AsyncTask从readyAsyncCalls遍历,添加到临时队列和异步运行队列, */
            for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
                AsyncCall asyncCall = i.next();
                if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
                if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity.
                i.remove();
                asyncCall.callsPerHost().incrementAndGet();
                executableCalls.add(asyncCall);
                runningAsyncCalls.add(asyncCall);
            }
            isRunning = runningCallsCount() > 0;
        }

	for (int i = 0, size = executableCalls.size(); i < size; i++) {
            AsyncCall asyncCall = executableCalls.get(i);
            // 执行异步请求
            asyncCall.executeOn(executorService());
	}
        return isRunning;
    }
    
    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;
  }
}
复制代码

AsyncCall是一个线程(class AsyncCall extends NamedRunnable),它并不是RealCall、或者Call接口的子类。
如上,asyncCall.executeOn(executorService()),executorService()创建了一个无限大Integer.MAX的线程池,用于执行异步请求运行。这个线程池作为AsyncCall.executeOn()的入参,后面AsyncCall就是使用该线程池让自己被执行起来,核心代码:executorService.execute(this),这里this是AsyncCall,它是个线程,使用线程池来运行AsyncCall线程,这样就做到了异步请求。
AsyncCall被线程池执行后,下面就应该看AsyncCall(的父类)的run()方法了。其内部执行了抽象方法execute(),所以在AsyncCall找到具体实现,如下:

class AsyncCall extends NamedRunnable {
    protected void execute() {
        ...
    	try {
            Response response = getResponseWithInterceptorChain();
            signalledCallback = true;
            responseCallback.onResponse(RealCall.this, response);
    	} finally {
             client.dispatcher().finished(this);
    	}
    }
}
复制代码

通过getResponseWithInterceptorChain()获取到请求结果,然后通过回调将response传递给请求调用者。

终于讲到最核心的getResponseWithInterceptorChain(),这也是填坑一号坑。这是责任链的写法,具体待追加。// TODO

Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());
    interceptors.add(new RetryAndFollowUpInterceptor(client));
    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));
    // 注意下面的originalRequest,这就是请求。填二号坑,虽然AsyncCall不直接持有request,但AsyncCall是RealCall的内部类,而RealCall是持有request的,所以AsyncCall是在这里,拿到请求的。
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
            originalRequest, this, client.connectTimeoutMillis(),
            client.readTimeoutMillis(), client.writeTimeoutMillis());
    boolean calledNoMoreExchanges = false;
    try {
        Response response = chain.proceed(originalRequest);
        if (transmitter.isCanceled()) {
            closeQuietly(response);
            throw new IOException("Canceled");
        }
        return response;
    } catch (IOException e) {
        calledNoMoreExchanges = true;
        throw transmitter.noMoreExchanges(e);
    } finally {
        if (!calledNoMoreExchanges) {
            transmitter.noMoreExchanges(null);
        }
    }
}
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享