从开始使用OkHttp已经很久了,它是一个很nice的网络框架,其功能强大,可进行失败重连,在连接中出问题时自动恢复。最近在复习的时候学了它的源码,以下主要是写它的使用和源码学习。
//异步请求
OkHttpClient client=new OkHttpClient();
Request request=new Request.Builder()
.url("url")
.addHeader("headerName","headerValue")//添加头部信息
.build();
Call call=client.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Request request, IOException e) {
//请求失败
}
//此时的OnResponse方法也不是在UI线程中
@Override
public void onResponse(Response response) throws IOException {
//请求成功
}
});
//同步请求,需放在子线程中
OkHttpClient mOkHttpClient=new OkHttpClient();
final Request request=new Request.Builder().url("url")
.build();
Call call=mOkHttpClient.newCall(request);
try {
Response response=call.execute();
if (response.isSuccessful()){
response.message();
response.code();
response.body().string();
}
} catch (IOException e) {
e.printStackTrace();
}
//异步请求
OkHttpClient client=new OkHttpClient();
FormEncodingBuilder builder=new FormEncodingBuilder();
builder.add("psw","123");//参数
builder.add("name","asendi");
Request request=new Request.Builder()
.url("url")
.post(builder.build())
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Request request, IOException e) {
}
//此时的OnResponse方法也不是在UI线程中
@Override
public void onResponse(Response response) throws IOException {
}
});
OkHttpClient client=new OkHttpClient();
File file=new File(path);
RequestBody fileBody=RequestBody.create(MediaType.parse("File/*"), file);
Request request=new Request.Builder()
.url("url")
.post(fileBody)
.build();
OkHttpClient client=new OkHttpClient();
File file=null;
RequestBody fileBody=
RequestBody.create(MediaType.parse("application/octet-stream"), file);
MultipartBuilder build=new MultipartBuilder()
.type(MultipartBuilder.FORM)
.addFormDataPart("username", "asendi")//添加参数
.addFormDataPart("uId", "1")
.addPart(Headers.of("Content-Disposition",
"form-data; name=\"username\""),
RequestBody.create(null,"阿森弟"))
.addPart(Headers.of("Content-Disposition",
"form-data; name=\"mFile\";" +
"filename=\"...\""), fileBody);
RequestBody requestBody=build.build();
public OkHttpClient() {
this(new Builder());
}
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;
}
在Builder中对里边的配置进行了初始化。
newCall(request)
@Override public Call newCall(Request request) {
return new RealCall(this, request, false /* for web socket */);
}
实际上是创建RealCall对象出来。
同步请求
@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);//从请求队列中移除
}
}
由以上代码可知做了四件事:
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);//责任链的开始
}
此方法里边创建了多个拦截器,而这些拦截器才是真正的主角,然后开始了责任链模式,各个拦截器执行特定的功能。
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
Connection connection) throws IOException {
......//错误检测省略
//开始逐个执行拦截器
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpCodec, connection, index + 1, request);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);//
// Confirm that the next interceptor made its required call to chain.proceed().
......
return response;
}
```java
* CacheInterceptor
CacheInterceptor是用于对缓存处理的,它的intercept方法如下:
```java
@Override public Response intercept(Chain chain) throws IOException {
Response cacheCandidate = cache != null
? cache.get(chain.request())
: null;//获取缓存中的响应
long now = System.currentTimeMillis();
//构建一个缓存策略
CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
Request networkRequest = strategy.networkRequest;
Response cacheResponse = strategy.cacheResponse;
if (cache != null) {
cache.trackResponse(strategy);
}
if (cacheCandidate != null && cacheResponse == null) {
closeQuietly(cacheCandidate.body()); // The cache candidate wasn't applicable. Close it.
}
// 如果没有缓存,并且没有网络请求
if (networkRequest == null && cacheResponse == null) {
return new Response.Builder()
.request(chain.request())
.protocol(Protocol.HTTP_1_1)
.code(504)
.message("Unsatisfiable Request (only-if-cached)")
.body(Util.EMPTY_RESPONSE)
.sentRequestAtMillis(-1L)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
}
// 如果只是没有网络请求
if (networkRequest == null) {
return cacheResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.build();
}
Response networkResponse = null;
try {
networkResponse = chain.proceed(networkRequest);
} finally {
// If we're crashing on I/O or otherwise, don't leak the cache body.
if (networkResponse == null && cacheCandidate != null) {
closeQuietly(cacheCandidate.body());
}
}
// 存在缓存
if (cacheResponse != null) {
if (networkResponse.code() == HTTP_NOT_MODIFIED) {
//发起请求获取响应
Response response = cacheResponse.newBuilder()
.headers(combine(cacheResponse.headers(), networkResponse.headers()))
.sentRequestAtMillis(networkResponse.sentRequestAtMillis())
.receivedResponseAtMillis(networkResponse.receivedResponseAtMillis())
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build();
networkResponse.body().close();
// 更新缓存
cache.trackConditionalCacheHit();
cache.update(cacheResponse, response);
return response;
} else {
closeQuietly(cacheResponse.body());
}
}
Response response = networkResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build();
if (HttpHeaders.hasBody(response)) {
CacheRequest cacheRequest = maybeCache(response, networkResponse.request(), cache);
response = cacheWritingResponse(cacheRequest, response);
}
return response;
}
以上方法主要功能如下:
根据请求获取缓存中对应的响应
构建缓存策略
发送请求,将获取到的响应进行缓存
CallServerInterceptor
CallServerInterceptor是发起请求并获取响应,它的intercept()方法如下:
@Override public Response intercept(Chain chain) throws IOException {
HttpCodec httpCodec = ((RealInterceptorChain) chain).httpStream();
StreamAllocation streamAllocation = ((RealInterceptorChain) chain).streamAllocation();
Request request = chain.request();
long sentRequestMillis = System.currentTimeMillis();
httpCodec.writeRequestHeaders(request);//发送请求头部
if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
Sink requestBodyOut = httpCodec.createRequestBody(request, request.body().contentLength());
BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
request.body().writeTo(bufferedRequestBody);//发送请求
bufferedRequestBody.close();
}
httpCodec.finishRequest();
//获取响应
Response response = httpCodec.readResponseHeaders()
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
int code = response.code();
......//做进一步的检测
return response;
}
此方法主要执行了:
异步请求
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
同样是进行同步检测防止同时多次发起请求,然后由Dispatcher开始进入请求
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
以上代码为:如果当前正在执行队列未超过限制数量,则直接放入线程池执行该任务,否则放到预备执行的异步任务队列中区。
AsyncCall是Call中的一个内部类,继承与NamedRunnable(run方法中执行execute方法,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方法有看了,所以看下finished方法
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();
}
}
主要是finished方法里边调用了promoteCalls方法
private void promoteCalls() {
if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall call = i.next();
if (runningCallsForHost(call) < maxRequestsPerHost) {
i.remove();
runningAsyncCalls.add(call);
executorService().execute(call);
}
if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
}
}
promoteCalls方法里面首先进行判断,如果正在执行的任务超过最大请求数,或者没有预备执行的任务,则直接返回。否则将预备队列的任务添加到正在执行队列,并且添加到线程池中执行。