okHttp源码分析-二 RetryAndFollowUpIntercept 重定向拦截器
okHttp源码分析-三 BridgeInterceptor 桥接拦截器
okHttp源码解析-四 缓存拦截器 CacheInterceptor
okhttp源码解析-五 链接拦截器 ConnectInterceptor
1.简单使用
创建okhttpClient对象
创建request对象
然后调用newCall
再调用enqueue()异步方法,里面传入一个监听回调方法。
OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder().url("http://baidu.com").build();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure( Call call, IOException e) {
}
@Override
public void onResponse( Call call, Response response) throws IOException {
}
});
2.源码分析
2.1 okhttpclient构造
public OkHttpClient() {
this(new Builder());
}
里面创建Builder对象
public Builder() {
dispatcher = new Dispatcher(); // 分发器对象,很重要
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
...
}
进入dispatcher
对象
public final class Dispatcher {
private int maxRequests = 64;
private int maxRequestsPerHost = 5;
private Runnable idleCallback;
/** Executes calls. Created lazily. */
private ExecutorService executorService;
/** Ready async calls in the order they'll be run. */
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
/** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
/** Running synchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
public Dispatcher(ExecutorService executorService) {
this.executorService = executorService;
}
public Dispatcher() {
}
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;
}
readyAsyncCalls 等待的异步队列
runningAsyncCalls 正在运行的异步队列
runningSyncCalls 正在运行的同步队列
同时还有线程池对象executorService
public ThreadPoolExecutor(int corePoolSize, //核心线程数量
int maximumPoolSize,//最大线程数量
long keepAliveTime,//存活的时间
TimeUnit unit,// 时间单位
BlockingQueue<Runnable> workQueue, // 锁队列
ThreadFactory threadFactory) { // 线程对象
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
上面创建核心对象涉及的类先记录,下面会用到。
2.2 new Request.Builder()
该对象使用建造者模式来构建,进入方法,默认请求方法get,创建了header对象
public Builder() {
this.method = "GET";
this.headers = new Headers.Builder();
}
new Request.Builder()使用了建造者模式,所以最终还是调用build();
public Request build() {
if (url == null) throw new IllegalStateException("url == null");
return new Request(this);
}
Request(Builder builder) {
this.url = builder.url;
this.method = builder.method;
this.headers = builder.headers.build();
this.body = builder.body;
this.tag = builder.tag != null ? builder.tag : this;
}
这些很简单,不叙述,大致就是准备请求头,url、body
2.3 newCall()
/**
* Prepares the {@code request} to be executed at some point in the future.
*/
@Override public Call newCall(Request request) {
// 创建RealCall对象
return new RealCall(this, request, false /* for web socket */);
}
RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
// 创建重定向拦截器,后面会讲
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
}
realcall对象就是真正请求对象的封装。创建RealCall的时候,创建了RetryAndFollowUpInterceptor类,就是重定向拦截器。后面说。
2.4 enqueue 异步方法
再往下看enqueue ,它是一个接口的方法,其实现就是realCall对象。
@Override
public void enqueue(Callback responseCallback) {
// 同步代码块
synchronized (this) {
如果已经执行,抛出异常
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
// 分发器执行异步操作
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
enqueue 方法开始异步处理队列的方法,正在运行的队列大小小于最大请求数量(64)且正在运行的host 小于最大请求host数量(5),把当前任务AsyncCall加入运行队列且执行任务,否则的话加入到准备队列中。
2.5 AsyncCall
该对象继承NamedRunnable,而NamedRunnable又是一个线程对象,所以就看run方法了
public abstract class NamedRunnable implements Runnable {
protected final String name;
public NamedRunnable(String format, Object... args) {
this.name = Util.format(format, args);
}
@Override public final void run() {
String oldName = Thread.currentThread().getName();
Thread.currentThread().setName(name);
try {
// 看重点,抽象方法,看子类喽,谁是它的子类,就是AsyncCall啊
execute();
} finally {
Thread.currentThread().setName(oldName);
}
}
protected abstract void 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 就是使用new CallBack对象,去响应成功和失败
responseCallback.onResponse(RealCall.this, response);
}
} catch (IOException e) {
...
} finally {
// 这也要看下
client.dispatcher().finished(this);
}
}
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);
return chain.proceed(originalRequest);
}
}
getResponseWithInterceptorChain 方法是okhttp的核心,里面是责任链模式。五个拦截器组成链式结构,去处理网络请求。
retryAndFollowUpInterceptor:当请求失败,会自动重连,或者重定向
BridgeInterceptor 主要处理请求头信息
CacheInterceptor 处理缓存信息
ConnectInterceptor 查找可用的连接
CallServerInterceptor 真正去请求服务器的拦截器
2.6 chain.proceed方法
责任链的执行方法proceed
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
Connection 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 && !sameConnection(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.
// 重点:创建一个新的拦截器的链式对象,然后传入index+1,意思就是取下一个
//拦截器对象,第一个对象就是重定向拦截器,然后调用intercept方法。
//因为Interceptor是个接口,所以就会调用接口的实现类去执行,
//就是重定向拦截器的interceptor方法。
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpCodec, connection, index + 1, request);
//
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
...
return response;
}
先获取第一个拦截器interceptors.get(index);然后调用intercept方法,传入下一个拦截器,嵌套调用。
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpCodec, connection, index + 1
如当重定向拦截器处理完任务后,还会再次调用realChain.proceed()方法,继续调用其他拦截器。至此,大体流程完毕。