02.OkHttp重要类说明
程序员文章站
2022-07-13 10:58:54
...
目录介绍
- 01.有哪些重要的类
- 02.OKHttpClient类
- 03.Request和Response类
- 04.Call接口类说明
- 05.RealCall类说明
- 06.Dispatcher类说明
- 07.主要流程图
01.有哪些重要的类
- OKHttpClient类
- Request类和Response类
- Call类和RealCall类
- Dispatcher类
02.OKHttpClient类说明
- 1、里面包含了很多对象,其实OKhttp的很多功能模块都包装进这个类,让这个类单独提供对外的API,这种外观模式的设计十分的优雅。外观模式。
- 2、而内部模块比较多,就使用了Builder模式(建造器模式)。Builder模式(建造器模式)
- 3、它的方法只有一个:newCall.返回一个Call对象(一个准备好了的可以执行和取消的请求)。
03.Request和Response类
- Request类说明
- Request抽象成请求数据
- Request包括Headers和RequestBody,而RequestBody是abstract的,他的子类是有FormBody(表单提交的)和MultipartBody(文件上传),分别对应了两种不同的MIME类型
FormBody :"application/x-www-form-urlencoded" MultipartBody:"multipart/"+xxx.
- Response类说明
- Response抽象成响应数据
- Response包括Headers和RequestBody,而ResponseBody是abstract的,所以他的子类也是有两个:RealResponseBody和CacheResponseBody,分别代表真实响应和缓存响应。
- 关于Headers说明,头部信息不是随便写的
- OKHttp的封装类Request和Response为了应用程序编程方便,会把一些常用的Header信息专门提取出来,作为局部变量。比如contentType,contentLength,code,message,cacheControl,tag…它们其实都是以name-value对的形势,存储在网络请求的头部信息中。
04.Call接口类说明
- Get或者Post请求,显示用builder构建了Request对象,然后执行了OKHttpClient.java的newCall方法,那么咱们就看看这个newCall里面都做什么操作?
//准备将来某个时候执行的{@code请求}。 @Override public Call newCall(Request request) { return RealCall.newRealCall(this, request, false /* for web socket */); }
- Call类详解
- 有道词典翻译该类注释:调用是准备执行的请求。call可以取消。由于此对象表示单个请求/响应对(流),因此不能执行两次。
- 主要是HTTP请求任务封装
- 可以说我们能用到的操纵基本上都定义在这个接口里面了,所以也可以说这个类是OKHttp类的核心类了。我们可以通过Call对象来操作请求,同步请求execute,异步请求enqueue,这两个想必都是很熟悉呢。而Call接口内部提供了Factory工厂方法模式(将对象的创建延迟到工厂类的子类去进行,从而实现动态配置)。
- Call接口提供了内部接口Factory(用于将对象的创建延迟到该工厂类的子类中进行,从而实现动态的配置)。
- Call类接口
- 继承Cloneable类,表明是可以clone的。接口中几个方法用的都非常多……
public interface Call extends Cloneable { Request request(); Response execute() throws IOException; void enqueue(Callback responseCallback); void cancel(); boolean isExecuted(); boolean isCanceled(); Call clone(); interface Factory { Call newCall(Request request); } }
05.RealCall类说明
5.1 RealCall构造
- RealCall类构造创建对象
- 在源码中,OKHttpClient实现了Call.Factory接口,返回了一个RealCall对象。那我们就来看下RealCall这个类。代码如下所示:
@Override public Call newCall(Request request) { return RealCall.newRealCall(this, request, false /* for web socket */); } 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; }
- 1、OkHttpClient的newCall方法里面new了RealCall的对象,但是RealCall的构造函数需要传入一个OKHttpClient对象和Request对象(PS:第三个参数false表示不是webSokcet)。因此RealCall包装了Request对象。所以RealCall可以很方便地使用这两个对象。
- 2、RealCall里面的两个关键方法是:execute 和 enqueue。分别用于同步和异步得执行网络请求。
- 3、RealCall还有一个重要方法是:getResponseWithInterceptorChain,添加拦截器,通过拦截器可以将一个流式工作分解为可配置的分段流程,既增加了灵活性也实现了解耦,关键还可以自有配置,非常完美。
5.2 execute方法调用
- client.newCall(request).execute();实际上执行的是RealCall的execute方法,现在咱们再回来看下RealCall的execute的具体实现
- 首先是判断call是否执行过,可以看出每个Call对象只能使用一次原则。
@Override 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); } }
- 然后接着看captureCallStackTrace方法
- RealCall的captureCallStackTrace() 又调用了Platform.get().getStackTraceForCloseable()。
- 其实是调用AndroidPlatform. getStackTraceForCloseable(String closer)方法。这里就不详细说了,后面详细说。
- 然后retryAndFollowUpInterceptor.setCallStackTrace(),在这个方法里面什么都没做就是set一个object进去。
- 综上所示captureCallStackTrace()这个方法其实是捕获了这个请求的StackTrace。
private void captureCallStackTrace() { Object callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()"); retryAndFollowUpInterceptor.setCallStackTrace(callStackTrace); } public Object getStackTraceForCloseable(String closer) { if (logger.isLoggable(Level.FINE)) { return new Throwable(closer); // These are expensive to allocate. } return null; }
5.3 enqueue异步方法
- client.newCall(request).enqueue();实际上执行的是RealCall的enqueue方法,现在咱们再回来看下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)); }
- 由于executed默认为false,所以先进行判断是否为true,为true则直接跑异常,没有则设置为true,可以看出executed这个是一个标志,标志这个请求是否已经正在请求中,合同步一样先调用了captureCallStackTrace();然后调用 client.dispatcher().enqueue(new AsyncCall(responseCallback));client.dispatcher()返回的是Dispatcher对象所以实际调用的是Dispatcher的enqueue()
06.Dispatcher类说明
6.1 execute同步方法源码分析
- 然后看一下关键性代码,如下所示。
- 进入了第一个核心类—Dispatcher的的execute方法。
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 { //最后需要调用finished方法结束 client.dispatcher().finished(this); }
- 看下OKHttpClient的dispatcher()方法的具体内容
- 发现client.dispatcher()返回的是Dispatcher对象,那么这个Dispatcher对象是何时创建的呢?
public Dispatcher dispatcher() { return dispatcher; }
- 在OkHttpClient.java里面Build类里面的构造函数里面
- 默认执行Builder()放到时候就创建了一个Dispatcher
//OkHttpClient.java public static final class Builder { public Builder() { dispatcher = new Dispatcher(); } }
- 接着看看Dispatcher类中executed执行方法
- 里面发现是runningSyncCalls执行了add方法,可以发现runningSyncCalls是ArrayDeque对象。
synchronized void executed(RealCall call) { runningSyncCalls.add(call); }
- 查看dispatcher里面怎么定义runningSyncCalls的
- 原来runningSyncCalls是双向队列啊,突然发现Dispatcher里面定义了三个双向队列,看**释,我们大概能明白readyAsyncCalls 是一个存放了等待执行任务Call的双向队列,runningAsyncCalls是一个存放异步请求任务Call的双向任务队列,runningSyncCalls是一个存放同步请求的双向队列。
/** 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<>();
- 接着看一下getResponseWithInterceptorChain源代码
- 发现 new了一个ArrayList,然后就是不断的add,后面 new了 RealInterceptorChain对象,最后调用了chain.proceed()方法。
Response getResponseWithInterceptorChain() throws IOException { // Build a full stack of interceptors. List<Interceptor> interceptors = new ArrayList<>(); //添加开发者应用层自定义的Interceptor interceptors.addAll(client.interceptors()); //这个Interceptor是处理请求失败的重试,重定向 interceptors.add(retryAndFollowUpInterceptor); //这个Interceptor工作是添加一些请求的头部或其他信息 //并对返回的Response做一些友好的处理(有一些信息你可能并不需要) interceptors.add(new BridgeInterceptor(client.cookieJar())); //这个Interceptor的职责是判断缓存是否存在,读取缓存,更新缓存等等 interceptors.add(new CacheInterceptor(client.internalCache())); //这个Interceptor的职责是建立客户端和服务器的连接 interceptors.add(new ConnectInterceptor(client)); if (!forWebSocket) { //添加开发者自定义的网络层拦截器 interceptors.addAll(client.networkInterceptors()); } interceptors.add(new CallServerInterceptor(forWebSocket)); //一个包裹这request的chain Interceptor.Chain chain = new RealInterceptorChain( interceptors, null, null, null, 0, originalRequest); //把chain传递到第一个Interceptor手中 return chain.proceed(originalRequest); }
- 看下RealInterceptorChain的构造函数。可以发现这里面仅仅只是一些赋值操作。
public RealInterceptorChain(List<Interceptor> interceptors, StreamAllocation streamAllocation, HttpCodec httpCodec, RealConnection connection, int index, Request request, Call call, EventListener eventListener, int connectTimeout, int readTimeout, int writeTimeout) { this.interceptors = interceptors; this.connection = connection; this.streamAllocation = streamAllocation; this.httpCodec = httpCodec; this.index = index; this.request = request; this.call = call; this.eventListener = eventListener; this.connectTimeout = connectTimeout; this.readTimeout = readTimeout; this.writeTimeout = writeTimeout; }
- 跟踪下chain.proceed()方法,看看做了什么。
public interface Interceptor { Response intercept(Chain chain) throws IOException; interface Chain { Request request(); Response proceed(Request request) throws IOException; @Nullable Connection connection(); Call call(); } }
- 由于Interceptor是个接口,所以应该是具体实现类RealInterceptorChain的proceed实现。
public final class RealInterceptorChain implements Interceptor.Chain { @Override 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"); } if (response.body() == null) { throw new IllegalStateException( "interceptor " + interceptor + " returned a response with no body"); } return response; } }
- 看到在proceed方面里面又new了一个RealInterceptorChain类的next对象,温馨提示下,里面的streamAllocation, httpCodec, connection都是null,所以这个next对象和chain最大的区别就是index属性值不同chain是0.而next是1,然后取interceptors下标为1的对象的interceptor。由从上文可知,如果没有开发者自定义的Interceptor时,首先调用的RetryAndFollowUpInterceptor,如果有开发者自己定义的interceptor则调用开发者interceptor。
6.2 enqueue异步方法
- 先看call类中的代码
- client.dispatcher()返回的是Dispatcher对象所以实际调用的是Dispatcher的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().enqueue方法操作了什么
- 根据源码和注释大家可以看到如果正在执行的异步请求小于64,并且请求同一个主机小于5的时候就先往正在运行的队列里面添加这个call,然后用线程池去执行这个call,否则就把他放到等待队列里面。执行这个call的时候,自然会去走到这个call的run方法。
private int maxRequests = 64; private int maxRequestsPerHost = 5; synchronized void enqueue(AsyncCall call) { //如果正在执行的请求小于设定值即64,并且请求同一个主机的request小于设定值即5 if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) { //添加到执行队列,开始执行请求 runningAsyncCalls.add(call); //获得当前线程池,没有则创建一个 executorService().execute(call); } else { //添加到等待队列中 readyAsyncCalls.add(call); } }
- 那么咱们看下AsyncCall.java这个类,而AsyncCall.java又继承自NamedRunnable.java咱们就一起看下他们的源码
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 { execute(); } finally { Thread.currentThread().setName(oldName); } } protected abstract void execute(); } final class AsyncCall extends NamedRunnable { private final Callback responseCallback; AsyncCall(Callback responseCallback) { super("OkHttp %s", redactedUrl()); this.responseCallback = responseCallback; } String host() { return originalRequest.url().host(); } Request request() { return originalRequest; } RealCall get() { return RealCall.this; } @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.onResponse(RealCall.this, response); } } catch (IOException e) { if (signalledCallback) { // Do not signal the callback twice! Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e); } else { responseCallback.onFailure(RealCall.this, e); } } finally { client.dispatcher().finished(this); } } }
- 上面看到NamedRunnable的构造方法设置了name在的run方法里面设定为当前线程的name,而NamedRunnable的run方法里面调用了它自己的抽象方法execute,由此可见NamedRunnable的作用就是设置了线程的name,然后回调子类的execute方法,那么我们来看下AsyncCall的execute方法。貌似好像又回到了之前同步的getResponseWithInterceptorChain()里面,根据返回的response来这只callback回调。
07.主要流程图
- 根据上面分析,大概流程图如下所示
上一篇: OKHttp源码解析(一)
下一篇: 04.OkHttp拦截器