OkHttp3源码分析(基于3.12.0)

简单使用流程

1、创建Requset对象
val URL : String = "http://www.baidu.com"
val request: Request = Request.Builder()
		.url(URL)
		.get()
		.build()

2、创建OkHttp对象

val okHttpClient = OkHttpClient.Builder().build()

3、创建Call对象
通过前面创建的request和okhttp创建Call对象

val call: Call = okHttpClient.newCall(request)

4、请求网络,分为两种,同步请求和异步请求。
(1)同步请求:

Thread(object : Runnable {
	override fun run() {
		val response: Response = call.execute()
		Log.d(TAG, "onResponse: " + response.body()!!.string());
	}

}).start();

调用execute()方法,会阻塞当前线程。因为现在Android高版本不允许在主线程请求网络,所以其实也是在子线程中请求的网络。
(2)异步请求:

call.enqueue(object : Callback {
	override fun onFailure(call: Call, e: IOException) {
		Log.d(TAG, "onFailure: ");
	}

	override fun onResponse(cal: Call, response: Response){
		Log.d(TAG, "onResponse: " + response.body()!!.string());
	}
});

调用enqueue()方法,结果通过回调返回。

源码分析

以异步请求为例子,看一下源码是怎么实现的。
先来看Request的创建过程。

val request: Request = Request.Builder()
		.url(URL)
		.get()
		.build()

使用工厂方法创建

public Builder() {
  	this.method = "GET";
  	this.headers = new Headers.Builder();
}

发现在Build()中,this.method默认返回了GET,说明如果不进行设置,默认这是一个Get请求。
接下来设置一些参数,比如通过url()设置http或https地址,get()表明这是一个get请求,也可以设置post()等,最后调用build()返回创建的Request对象。

public Request build() {
	if (url == null) throw new IllegalStateException("url == null");
	return new Request(this);
}

接下来创建OkHttpClient对象,也可以通过Build().build()的工厂方法模式创建,不具体写了。

val okHttpClient = OkHttpClient.Builder().build()

接着创建call

val call: Call = okHttpClient.newCall(request)

进到newCall()方法中。

@Override public Call newCall(Request request) {
	return RealCall.newRealCall(this, request, false /* for web socket */);
}

调用了RealCall类的newRealCall()方法。

static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
	// Safely publish the Call instance to the EventListener.
	RealCall call = new RealCall(client, originalRequest, forWebSocket);
	call.eventListener = client.eventListenerFactory().create(call);
	return call;
}

创建并返回了一个RealCall类型的对象。ReallCal其实是一个Call的实现类。

final class RealCall implements Call {
	...
}

接着就是请求网络了,这里分析的是异步请求enqueue()。

call.enqueue(object : Callback {
	override fun onFailure(call: Call, e: IOException) {
		Log.d(TAG, "onFailure: ");
	}

	override fun onResponse(cal: Call, response: Response){
		Log.d(TAG, "onResponse: " + response.body()!!.string());
	}
});

进到RealCall的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));
}

client.dispatcher()返回了前面创建的Dispatcher对象。先来看一下enqueue()方法中的参数,创建了一个AsyncCall类型的对象。

final class AsyncCall extends NamedRunnable {
	AsyncCall(Callback responseCallback) {
		super("OkHttp %s", redactedUrl());
		this.responseCallback = responseCallback;
	}
}

AsyncCall继承自NamedRunnable,而NamedRunnable继承自Runnable。
回到enqueue方法中,进到Dispatcher的enqueue()方法中。

void enqueue(AsyncCall call) {
	synchronized (this) {
		readyAsyncCalls.add(call);
	}
	promoteAndExecute();
}

首先将Callback加入到未执行队列中,然后调用了promoteAndExecute()方法。

private boolean promoteAndExecute() {
	assert (!Thread.holdsLock(this));

	List<AsyncCall> executableCalls = new ArrayList<>();
	boolean isRunning;
	synchronized (this) {
	for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
		AsyncCall asyncCall = i.next();

		if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
		if (runningCallsForHost(asyncCall) >= maxRequestsPerHost) continue; // Host max capacity.

		i.remove();
		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;
}

首先创建一个局部变量的队列executableCalls,通过for循环去遍历readyAsyncCalls也就是未执行任务列表。当正在执行的任务数未达到设定的最大值maxRequests并且相同host下最多运行的请求数未达到最大值maxRequestsPerHost的话,将当前遍历到的任务从未执行队列readyAsyncCalls中移除,并将其加入到执行队列runningAsyncCalls和局部变量队列executableCalls中。再次通过一个for循环取出任务,调用executeOn()方法。先来看一下executorService()。

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;
}

创建了一个线程池。接着进到AsyncCall的executeOn()方法中

void executeOn(ExecutorService executorService) {
	assert (!Thread.holdsLock(client.dispatcher()));
	boolean success = false;
	 try {
		executorService.execute(this);
		success = true;
	 } catch (RejectedExecutionException e) {
		InterruptedIOException ioException = new InterruptedIOException("executor rejected");
		ioException.initCause(e);
		eventListener.callFailed(RealCall.this, ioException);
		responseCallback.onFailure(RealCall.this, ioException);
	} finally {
		if (!success) {
			client.dispatcher().finished(this); // This call is no longer running!
		}
	}
}

在try块中调用了线程池的execute方法。这个时候应该会执行对应线程的run()方法,但具体执行的是哪个线程呢。前面看到过AsyncCall继承自NamedRunnable。进到NamedRunnable类中,发现了run()方法。

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);
		}
	}
}
protected abstract void execute();

在run()中调用了execute()方法,这是NamedRunnable类的一个抽象方法,具体的实现由子类完成,就是AsyncCall()类,也就是executorService.execute(this)中的this。这其实是一个模板方法模式。
进到子类AsyncCall中的execute()方法。

@Override protected void execute() {
  	boolean signalledCallback = false;
  	timeout.enter();
  	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) {
		e = timeoutExit(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 {
		client.dispatcher().finished(this);
  	}
}

这是一个try-catch-finally块,无论是否抛出异常,都会执行finally中的代码。在finally中调用了Dispatch的finished()方法。

void finished(AsyncCall call) {
	finished(runningAsyncCalls, call);
}

继续调用finished()方法。

private <T> void finished(Deque<T> calls, T call) {
	Runnable idleCallback;
	synchronized (this) {
	  	if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
	  	idleCallback = this.idleCallback;
	}

	boolean isRunning = promoteAndExecute();

	if (!isRunning && idleCallback != null) {
	  	idleCallback.run();
	}
}

又调用了promoteAndExecute()方法,如果还有未执行的任务的话,会继续重复上面的步骤执行下一个任务。所以异步调用中,一个请求的阻塞不会影响到其他的请求。
回到上面的execute()方法,继续看真正开始请求网络的地方。在try中调用了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));
	
	//index = 0
	Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
		originalRequest, this, eventListener, client.connectTimeoutMillis(),
		client.readTimeoutMillis(), client.writeTimeoutMillis());

	return chain.proceed(originalRequest);
}

从名字可以看出,与拦截器有关。首先创建了一个拦截器列表interceptors,并向其中添加了一系列的拦截器。紧接着创建了一个RealInterceptorChain对象,注意其构造函数中第5个参数index传入了0。然后调用了proceed()方法。这是一个接口Interceptor.Chain中的方法,由实现了该接口的类来具体实现,这里是RealInterceptorChain类。

public interface Interceptor {
    Response intercept(Chain chain) throws IOException;
    
    interface Chain {
		Request request();

		Response proceed(Request request) throws IOException;
		...
	}
}

调用了RealInterceptorChain类的proceed()方法。

@Override public Response proceed(Request request) throws IOException {
	return proceed(request, streamAllocation, httpCodec, connection);
}

进到proceed()方法。

public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
  RealConnection connection) throws IOException {
	if (index >= interceptors.size()) throw new AssertionError();

	calls++;
	...
	// Call the next interceptor in the chain.
	RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
		connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
		writeTimeout);
	Interceptor interceptor = interceptors.get(index);
	Response response = interceptor.intercept(next);
	...
	return response;
}

直接看主要代码,又创建了一个RealInterceptorChain对象,但是注意到构造方法第五个参数index传入的是index + 1。然后从拦截器列表中取出第index项,默认情况用户没有添加自定义拦截器时,第一次取出的拦截器为重定向拦截器RetryAndFollowUpInterceptor。因为这些默认的拦截器类都是实现了Interceptor接口。所以这里调用的是RetryAndFollowUpInterceptor类的intercept()方法。

@Override public Response intercept(Chain chain) throws IOException {
	Request request = chain.request();
	RealInterceptorChain realChain = (RealInterceptorChain) chain;
	Call call = realChain.call();
	EventListener eventListener = realChain.eventListener();

	StreamAllocation streamAllocation = new StreamAllocation(client.connectionPool(),
		createAddress(request.url()), call, eventListener, callStackTrace);
	this.streamAllocation = streamAllocation;

	int followUpCount = 0;
	Response priorResponse = null;
	while (true) {
	  if (canceled) {
		streamAllocation.release();
		throw new IOException("Canceled");
	  }

	  Response response;
	  boolean releaseConnection = true;
	  try {
		//调用了RealInterceptorChain的proceed()方法
		response = realChain.proceed(request, streamAllocation, null, null);
		releaseConnection = false;
	  } catch (RouteException e) {
		// The attempt to connect via a route failed. The request will not have been sent.
		if (!recover(e.getLastConnectException(), streamAllocation, false, request)) {
		  throw e.getFirstConnectException();
		}
		releaseConnection = false;
		continue;
	  } catch (IOException e) {
		// An attempt to communicate with a server failed. The request may have been sent.
		boolean requestSendStarted = !(e instanceof ConnectionShutdownException);
		if (!recover(e, streamAllocation, requestSendStarted, request)) throw e;
		releaseConnection = false;
		continue;
	  } finally {
		// We're throwing an unchecked exception. Release any resources.
		if (releaseConnection) {
		  streamAllocation.streamFailed(null);
		  streamAllocation.release();
		}
	  }

	  // Attach the prior response if it exists. Such responses never have a body.
	  if (priorResponse != null) {
		response = response.newBuilder()
			.priorResponse(priorResponse.newBuilder()
					.body(null)
					.build())
			.build();
	  }

	  Request followUp;
	  try {
		followUp = followUpRequest(response, streamAllocation.route());
	  } catch (IOException e) {
		streamAllocation.release();
		throw e;
	  }

	  if (followUp == null) {
		streamAllocation.release();
		return response;
	  }

	  closeQuietly(response.body());

	  if (++followUpCount > MAX_FOLLOW_UPS) {
		streamAllocation.release();
		throw new ProtocolException("Too many follow-up requests: " + followUpCount);
	  }

	  if (followUp.body() instanceof UnrepeatableRequestBody) {
		streamAllocation.release();
		throw new HttpRetryException("Cannot retry streamed HTTP body", response.code());
	  }

	  if (!sameConnection(response, followUp.url())) {
		streamAllocation.release();
		streamAllocation = new StreamAllocation(client.connectionPool(),
			createAddress(followUp.url()), call, eventListener, callStackTrace);
		this.streamAllocation = streamAllocation;
	  } else if (streamAllocation.codec() != null) {
		throw new IllegalStateException("Closing the body of " + response
			+ " didn't close its backing stream. Bad interceptor?");
	  }

	  request = followUp;
	  priorResponse = response;
	}
}

发现再次调用了realChain的proceed()方法,而这个realChain正是我们创建的那个第五个参数为index + 1的对象。重新回到RealInterceptorChain类中的proceed()方法中,这里就不贴代码了,直接看上面的。重复的流程,构造方法中将index加1,interceptors.get(index)获取到下一个拦截器。interceptors列表中下一个拦截器是
BridgeInterceptor桥接拦截器,和前面RetryAndFollowUpInterceptor一样的套路,直接进到
BridgeInterceptor类的intercept()方法。

@Override public Response intercept(Chain chain) throws IOException {
	Request userRequest = chain.request();
	Request.Builder requestBuilder = userRequest.newBuilder();

	RequestBody body = userRequest.body();
	if (body != null) {
	  MediaType contentType = body.contentType();
	  if (contentType != null) {
		requestBuilder.header("Content-Type", contentType.toString());
	  }

	  long contentLength = body.contentLength();
	  if (contentLength != -1) {
		requestBuilder.header("Content-Length", Long.toString(contentLength));
		requestBuilder.removeHeader("Transfer-Encoding");
	  } else {
		requestBuilder.header("Transfer-Encoding", "chunked");
		requestBuilder.removeHeader("Content-Length");
	  }
	}

	if (userRequest.header("Host") == null) {
	  requestBuilder.header("Host", hostHeader(userRequest.url(), false));
	}

	if (userRequest.header("Connection") == null) {
	  requestBuilder.header("Connection", "Keep-Alive");
	}

	// If we add an "Accept-Encoding: gzip" header field we're responsible for also decompressing
	// the transfer stream.
	boolean transparentGzip = false;
	if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
	  transparentGzip = true;
	  requestBuilder.header("Accept-Encoding", "gzip");
	}

	List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
	if (!cookies.isEmpty()) {
	  requestBuilder.header("Cookie", cookieHeader(cookies));
	}

	if (userRequest.header("User-Agent") == null) {
	  requestBuilder.header("User-Agent", Version.userAgent());
	}
	//添加了一些请求头,继续调用proceed()
	Response networkResponse = chain.proceed(requestBuilder.build());

	HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());

	Response.Builder responseBuilder = networkResponse.newBuilder()
		.request(userRequest);

	if (transparentGzip
		&& "gzip".equalsIgnoreCase(networkResponse.header("Content-Encoding"))
		&& HttpHeaders.hasBody(networkResponse)) {
	  GzipSource responseBody = new GzipSource(networkResponse.body().source());
	  Headers strippedHeaders = networkResponse.headers().newBuilder()
		  .removeAll("Content-Encoding")
		  .removeAll("Content-Length")
		  .build();
	  responseBuilder.headers(strippedHeaders);
	  String contentType = networkResponse.header("Content-Type");
	  responseBuilder.body(new RealResponseBody(contentType, -1L, Okio.buffer(responseBody)));
	}

	return responseBuilder.build();
}

发现一样的套路,接着会调用下一个拦截器的intercept()方法。这其实是一个责任链模式,通过每次创建RealInterceptorChain对象时将index加1,不断取出并执行interceptors队列中的下一个拦截器,完全是按着一开始的加入顺序执行的。在经过各个拦截器一系列的处理后,在最后一个CallServerInterceptor拦截器中,访问了网络并得到了网络的相应。
而且可以发现,当最终得到来自网络的响应后,会按着请求时经过拦截器顺序的反序再过一遍拦截器,做一些处理。大体流程如下图所示。

1
2
3
4
5
6
7 访问网络
8 得到网络数据
9
10
11
12
13
14
用户请求网络
自定义拦截器
重定向拦截器
桥接拦截器
缓存拦截器
连接拦截器
访问网络拦截器
网络

总结

整个OkHttp请求网络的流程大体分析了一下。个人觉得可以分为三部分

  1. 通过两个工厂方法模式创建了Request和OkHttp对象
  2. 通过模板方法模式调用了线程池,发起不同的异步网络请求
  3. 通过责任链模式对网络请求和响应添加拦截器

有什么不对的地方欢迎大家指出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值