okhttp使用
app下gradle文件中引入okhttp
//引入okhttp
api 'com.squareup.okhttp3:okhttp:3.5.0'
okhttp同步请求
//1.创建okhttp对象
OkHttpClient client = new OkHttpClient.Builder()
.readTimeout(5, TimeUnit.SECONDS)
.build();
//2.创建请求对象
Request request = new Request.Builder()
.url("https://www.baidu.com")
.get()
.build();
//3.将request封装成call请求对象
Call call = client.newCall(request);
try {
//4.执行call请求 获取响应
Response response = call.execute();
//输出报文
System.out.println(request.body().toString());
} catch (IOException e) {
e.printStackTrace();
}
以上即为okhttp请求网络的四个步骤,那么在这四个步骤的背后,okhttp做了哪些工作呢?
1.okhttp构造函数
//分发请求进入执行队列,核心类
final Dispatcher dispatcher;
//请求代理
final Proxy proxy;
//协议列表
final List<Protocol> protocols;
//连接列表
final List<ConnectionSpec> connectionSpecs;
//拦截器列表
final List<Interceptor> interceptors;
//网络拦截器列表
final List<Interceptor> networkInterceptors;
final ProxySelector proxySelector;
//cookie的保存策略
final CookieJar cookieJar;
//缓存
final Cache cache;
final InternalCache internalCache;
//通讯工厂
final SocketFactory socketFactory;
final SSLSocketFactory sslSocketFactory;
//安全证书管理者
final CertificateChainCleaner certificateChainCleaner;
//主机域名验证
final HostnameVerifier hostnameVerifier;
final CertificatePinner certificatePinner;
final Authenticator proxyAuthenticator;
final Authenticator authenticator;
//连接池
final ConnectionPool connectionPool;
//域名解析器
final Dns dns;
final boolean followSslRedirects;
final boolean followRedirects;
final boolean retryOnConnectionFailure;
final int connectTimeout;
final int readTimeout;
final int writeTimeout;
//发送请求时间间隔
final int pingInterval;
public OkHttpClient() {
this(new Builder());
}
//builder构建模式,初始化okhttp一系列属性值
OkHttpClient(Builder builder) {
this.dispatcher = builder.dispatcher;
this.proxy = builder.proxy;
this.protocols = builder.protocols;
this.connectionSpecs = builder.connectionSpecs;
this.interceptors = Util.immutableList(builder.interceptors);
this.networkInterceptors = Util.immutableList(builder.networkInterceptors);
this.proxySelector = builder.proxySelector;
this.cookieJar = builder.cookieJar;
this.cache = builder.cache;
this.internalCache = builder.internalCache;
this.socketFactory = builder.socketFactory;
boolean isTLS = false;
for (ConnectionSpec spec : connectionSpecs) {
isTLS = isTLS || spec.isTls();
}
if (builder.sslSocketFactory != null || !isTLS) {
this.sslSocketFactory = builder.sslSocketFactory;
this.certificateChainCleaner = builder.certificateChainCleaner;
} else {
X509TrustManager trustManager = systemDefaultTrustManager();
this.sslSocketFactory = systemDefaultSslSocketFactory(trustManager);
this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
}
this.hostnameVerifier = builder.hostnameVerifier;
this.certificatePinner = builder.certificatePinner.withCertificateChainCleaner(
certificateChainCleaner);
this.proxyAuthenticator = builder.proxyAuthenticator;
this.authenticator = builder.authenticator;
this.connectionPool = builder.connectionPool;
this.dns = builder.dns;
this.followSslRedirects = builder.followSslRedirects;
this.followRedirects = builder.followRedirects;
this.retryOnConnectionFailure = builder.retryOnConnectionFailure;
this.connectTimeout = builder.connectTimeout;
this.readTimeout = builder.readTimeout;
this.writeTimeout = builder.writeTimeout;
this.pingInterval = builder.pingInterval;
}
public OkHttpClient build() {
return new OkHttpClient(this);
}
//这是builder类中的构造方法,初始化okhttp
public Builder() {
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
proxySelector = ProxySelector.getDefault();
cookieJar = CookieJar.NO_COOKIES;
socketFactory = SocketFactory.getDefault();
hostnameVerifier = OkHostnameVerifier.INSTANCE;
certificatePinner = CertificatePinner.DEFAULT;
proxyAuthenticator = Authenticator.NONE;
authenticator = Authenticator.NONE;
connectionPool = new ConnectionPool();
dns = Dns.SYSTEM;
followSslRedirects = true;
followRedirects = true;
retryOnConnectionFailure = true;
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
pingInterval = 0;
}
以上okhttp构造函数主要做一些初始化操作,配置一些okhttp属性,完成okhttp对象的创建。
2.创建Request请求对象
由第二步可知,Request的构建也是采用builder模式创建,看下源码
final HttpUrl url;
final String method;
final Headers headers;
final RequestBody body;
final Object tag;
private volatile CacheControl cacheControl; // Lazily initialized.
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;
}
public Request build() {
if (url == null) throw new IllegalStateException("url == null");
return new Request(this);
}
这里主要也是构建request,初始化一些属性,包括请求地址url,请求方式,请求头,tag值(作用是用于取消网络请求的,具体会在后面有介绍)等等
3.将request封装为call请求
okhttpclient类
@Override public Call newCall(Request request) {
return new RealCall(this, request, false /* for web socket */);
}
RealCall类
final class RealCall implements Call {
final OkHttpClient client;
//拦截器
final RetryAndFollowUpInterceptor retryAndFollowUpInterceptor;
/** The application's original request unadulterated by redirects or auth headers. */
final Request originalRequest;
//标志位 是否为webSocket协议
final boolean forWebSocket;
// Guarded by this.
private boolean executed;
RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
}
}
可以看到RealCall继承自Call类,并对其进一步封装。
4.执行call请求
第四步是整个okhttp的核心步骤,这一步的背后进行了大量的操作。
RealCall类
final class RealCall implements Call {
final OkHttpClient client;
final RetryAndFollowUpInterceptor retryAndFollowUpInterceptor;
/** The application's original request unadulterated by redirects or auth headers. */
final Request originalRequest;
final boolean forWebSocket;
// Guarded by this.
private boolean executed;
RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
}
@Override public Request request() {
return originalRequest;
}
//执行请求
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} finally {
client.dispatcher().finished(this);
}
}
private void captureCallStackTrace() {
Object callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()");
retryAndFollowUpInterceptor.setCallStackTrace(callStackTrace);
}
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
}
在RealCall中的execute方法中,最重要的两行代码:
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
client.dispatcher().executed(this):client.dispatcher()是okhttp的核心类,主要是将Call请求添加到执行队列中
/** Used by {@code Call#execute} to signal it is in-flight. */
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
getResponseWithInterceptorChain():此方法创建一系列的拦截器,将realCall请求封装为真正的网络请求,最后请求服务器返回数据。
这里很多人有疑问:在加入到队列中后,执行getResponseWithInterceptorChain()获取数据,然后执行return返回数据,runningSyncCalls队列中并没有释放掉已经完成的请求。其实不然,在return response之后,finally还是会执行,释放已完成的请求。
Java finally语句到底是在return之前还是之后执行?
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
//将所有客户端自定义的拦截器加入拦截器列表
interceptors.addAll(client.interceptors());
//retryAndFollowUpInterceptor这个拦截器主要重试失败请求
interceptors.add(retryAndFollowUpInterceptor);
//加入请求头信息,cookie策略,压缩协议等
interceptors.add(new BridgeInterceptor(client.cookieJar()));
//判断缓存是否过期,若有缓存则返回缓存数据
interceptors.add(new CacheInterceptor(client.internalCache()));
//建立网络连接
interceptors.add(new ConnectInterceptor(client));
//如果不是websocket协议,就加入用户自定义的网络拦截器
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);
}
将整个拦截链执行完毕后,会返回Response数据,整个访问网络请求就执行完毕。
重点:在以上同步代码当中,没有切换任何线程,所以如果在android平台上运行同步请求,请记住一定要另起线程(子线程)进行同步请求。
okhttp异步请求
以为为okhttp的异步请求,前三步与同步请求一致
OkHttpClient client = new OkHttpClient.Builder()
.readTimeout(5, TimeUnit.SECONDS)
.build();
Request request = new Request.Builder().url("https://www.baidu.com")
.get().build();
Call call = client.newCall(request);
//请求入队列
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
System.out.println("Fail");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
System.out.println(response.body().string());
}
});
那么call.enqueue到底干了那些事情呢?
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
首先判断这个call是否已经执行,然后调用dispatcher().enqueue()将其加入执行队列,注意这里的传入的参数是AsyncCall,它是将RealCall封装为Runnable对象(AsyncCall继承自NamedRunnable,而NamedRunable继承自Runable)。
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();
}
言归正传,看看dispatcher.enqueue()方法中做了什么工作。
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
如果异步队列中的请求数量小于最大请求数量,则将请求加入到异步执行队列,并调用线程池执行此任务;否则将此任务加入到等待队列中等待执行。当线程池执行到此请求任务时,会执行asyncCall.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.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);
}
}
首先执行的又是我们熟悉的getResponseWithInterceptorChain(),然后判断retryAndFollowUpInterceptor重试拦截器是否取消,若取消则说明责任链只执行到retryAndFollowUpInterceptor,抛出异常,执行失败;否则执行成功返回数据,回调onResponse(此回调在子线程);最后在finally模块当中执行finish()。
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
int runningCallsCount;
Runnable idleCallback;
synchronized (this) {
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
if (promoteCalls) promoteCalls();
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
}
okhttp执行流程图在finish()函数中,移除刚刚执行完成的异步任务,并且通过promoteCalls()函数判断执行队列是否已满;若未满,则将遍历取出等待队列中的任务添加到执行队列中,直到执行队列达到最大数量。
okhttp网络框架源码浅析(二)
网友评论