OKHttp系列七、OKHttp的拦截器链

1、OKHttp的拦截器有5种:

RetryAndFollowUpInterceptor:重试和请求失败后重定向拦截器。主要作用是:初始化拦截器数据的工作,创建StreamAllocation对象。
BridgeInterceptor:桥接和适配拦截器;补充用户创建使用过程中缺少的OKHttp请求头。
CacheInterceptor:处理缓存的一些功能。
ConnectInterceptor:核心拦截器之一,网络交互的关键。他是CallServerInterceptor拦截器的基础。主要负责建立可用的网络连接。
CallServerInterceptor:核心拦截器之二,网络交互的关键。主要负责将网络请求写进网络IO流中,并从网络IO流中读取服务端返回给我们的数据。

他们的关系如下:
在这里插入图片描述
2、拦截器的作用:

其实无论是同步请求,还是异步请求,拦截器的作用都是类似的,区别不大。这里我们以同步请求为例:

public Response execute() throws IOException {
	synchronized (this) {
		if (executed) throw new IllegalStateException("Already Executed");
		executed = true;
	}
	captureCallStackTrace();
	eventListener.callStart(this);
	try {
		client.dispatcher().executed(this);
		Response result = getResponseWithInterceptorChain();
		if (result == null) throw new IOException("Canceled");
		return result;
	} catch (IOException e) {
		eventListener.callFailed(this, e);
		throw e;
	} finally {
		client.dispatcher().finished(this);
	}
}

上面这段代码肯定不陌生,之前我们重点分析的是try{}代码块里面的第一行代码和finally{}代码块里面的代码,现在我们重点分析try{}代码块里面的第二行代码:

Response result = getResponseWithInterceptorChain(); 

他的最终目的是返回网络请求的结果Response,他的源码如下:

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

该方法的第一个主要工作就是通过变量interceptors构建连接器集合。然后通过依次执行每一个不同功能的拦截器来获取服务器的响应返回,这时拦截器的主旨。

addAll方法是添加用户自定义的拦截器;
第一个add方法是添加系统的重试和请求失败后重定向拦截器;
第二个add方法用于添加桥接和适配拦截器,如果用户自己有配置的话,就用用户自定义的,否则添加系统自带的;
第三个add方法用于添加缓存拦截器,添加类型同桥接和适配拦截器;
第四个add方法用于添加连接拦截器,添加类型同桥接和适配拦截器;if判断语句则是添加网络拦截器(OKHttp中,拦截器分两种:ApplicationInterceptor应用拦截器和networkInterceptor网络拦截器,网络拦截器又分前面提到的5中拦截器)。

然后是添加与服务器数据交互回调的拦截器。最后将拦截器集合通过构造方法统一添加到Interceptor.Chain chain对象里面。最后chain对象再调用proceed方法获取Response请求结果。proceed方法两个作用:一是获取Response请求结果;二是创建下一个拦截器链。proceed方法源码如下:

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

public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec, RealConnection connection) throws IOException {
	if (index >= interceptors.size()) throw new AssertionError();
	
	calls++;
	
	// If we already have a stream, confirm that the incoming request will use it.
	if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
		throw new IllegalStateException("network interceptor " + interceptors.get(index - 1) + " must retain the same host and port");
	}
	
	// If we already have a stream, confirm that this is the only call to chain.proceed().
	if (this.httpCodec != null && calls > 1) {
		throw new IllegalStateException("network interceptor " + interceptors.get(index - 1) + " must call proceed() exactly once");
	}
	
	/**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);
	
	// Confirm that the next interceptor made its required call to chain.proceed().
	if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
		throw new IllegalStateException("network interceptor " + interceptor + " must call proceed() exactly once");
	}
	
	// Confirm that the intercepted response isn't null.
	if (response == null) {
		throw new NullPointerException("interceptor " + interceptor + " returned null");
	}
	
	// Confirm that the intercepted response.body() isn't null.
	if (response.body() == null) {
		throw new IllegalStateException("interceptor " + interceptor + " returned a response with no body");
	}
	return response;
}

这段代码比较长,但是大部分都是抛异常的处理,也就是if判断的部分,真正产生左右的只有以/****/方式添加注释的部分代码;

next是一个拦截器的链,他与Interceptor.Chain chain = new RealInterceptorChain()的链的区别是:
——next拦截器链的构造方法里面的参数是index + 1,chain的这个参数是0;之所以这么做,是因为next拦截器链进过+1操作,通过intercept方法,能够实现依次调用下一个拦截器链。

3、拦截器链之间是如何衔接的?

拦截器链构建完成后,会调用
Response response = interceptor.intercept(next);
进行数据请求,我们先看retryAndFollowUpInterceptor重定向拦截器里面的intercept方法,重定向拦截器RetryAndFollowUpInterceptor的intercept方法源码很长,这里就不贴出来了。它里面有这样的代码存在:

……
RealInterceptorChain realChain = (RealInterceptorChain) chain;
……
Response response = realChain.proceed(request, streamAllocation, null, null);
……

我们可以看到最后一行代码又是执行的是proceed方法,因此我们可以发现:
在RealCall.java的 execute()方法里面调用了以下这个方法:

Response result = getResponseWithInterceptorChain();

而getResponseWithInterceptorChain()方法里面又在完成了一系列的拦截链构建后,调用chain.proceed()方法,而chain是RealInterceptorChain的对象,RealInterceptorChain.java里面proceed方法里面又通过index + 1的方式构建下一个拦截器链,并把本拦截器获取到的Response信息返回回去,然后调用intercept方法,然后我们拦截器链中的第一个拦截器——重定向拦截器里面的intercept方法中又通过RealInterceptorChain对象realChain调用了proceed方法:ealChain.proceed(),这样拦截器链之间的衔接调用就完美的实现了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值