Okhttp源码分析-流程分析(1)-基于最新okhttp3.4.1

OkHttp源码解析

第一次写源码分析,有许多不完善的地方,大致贴了一下流程,仅供学习,大神请飘过。欢迎指正,共同进步。

先看MainActivity,创建了一个简单的请求。

packagecom.analysis.lanzhiming.okhttp_source_analysis;


public class MainActivityextends AppCompatActivity{

   
private OkHttpClientclient;
   
@Override
   
protected void onCreate(BundlesavedInstanceState){
       
super.onCreate(savedInstanceState);
       
setContentView(R.layout.activity_main);
//网络请求
       
httpGet();
   
}

   
private void httpGet(){
       
Request request= newRequest.Builder()
                
.url("https://www.csdn.net/")
               
.build();
       
client =new OkHttpClient();
       
client.newCall(request).enqueue(newCallback() {

           
@Override
           
public void onFailure(Callcall, IOException e){

            }

           
@Override
           
public void onResponse(Callcall, Response response)throws IOException{
               
Log.e("测试okhttp ",response.toString());
           
}
        }
);
   
}
}

 

首先关注newCall

/**
 * Prepares the {@code request} to be executed at some point in the future.
 */
  @Override public Call newCall(Request request) {
  return new RealCall(this, request);
  }

 

调用了RealCall类,关注enqueue

@Override public void enqueue(Callback responseCallback) {
  synchronized (this) {
    if (executed) throw new IllegalStateException("Already Executed");
    executed = true;
  }
  client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

 

 

再关注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 实现了NamedRunnable接口

final class AsyncCall extends NamedRunnable {
  private final Callback responseCallback;
  
  private AsyncCall(Callback responseCallback) {
    super("OkHttp %s", redactedUrl().toString());
    this.responseCallback = responseCallback;
  }

 

我们可以看下NamedRunnable实现流程,实际上是调用了在run方法中的execute()方法

@Override public final void run() {
  String oldName = Thread.currentThread().getName();
  Thread.currentThread().setName(name);
  try {
    execute();
  } finally {
    Thread.currentThread().setName(oldName);
  }
}

 

所以这里重点关注execute()方法

回到RealCall这个类,查看内部类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);
  }
}

 

这里我们关注到Response对象

Response response = getResponseWithInterceptorChain();

 

看getResponseWithInterceptorChain()方法

private 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 (!retryAndFollowUpInterceptor.isForWebSocket()) {
    interceptors.addAll(client.networkInterceptors());
  }
  interceptors.add(new CallServerInterceptor(
      retryAndFollowUpInterceptor.isForWebSocket()));
  
  Interceptor.Chain chain = new RealInterceptorChain(
      interceptors, null, null, null, 0, originalRequest);
  return chain.proceed(originalRequest);
  }

 

前面的intercepters构建一些拦截器(非常重要,后面的流程都是跟这个拦截器[List]相关)

这里关注最后两句

Interceptor.Chain chain = new RealInterceptorChain(
    interceptors, null, null, null, 0, originalRequest);
  return chain.proceed(originalRequest);

 

查看RealInterceptorChain 类proceed()方法

@Override public Response proceed(Request request) throws IOException {
  return proceed(request, streamAllocation, httpStream, connection);
  }
  
  public Response proceed(Request request, StreamAllocation streamAllocation, HttpStream httpStream,
    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.httpStream != 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.httpStream != 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, httpStream, 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().
  if (httpStream != 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");
  }
  
  return response;
  }

 

 

前面我们添加了一系列的拦截器,这些都是Intercepter的具体实现

interceptors.add(retryAndFollowUpInterceptor);
  interceptors.add(new BridgeInterceptor(client.cookieJar()));
  interceptors.add(new CacheInterceptor(client.internalCache()));
  interceptors.add(new ConnectInterceptor(client));
interceptors.add(new CallServerInterceptor(
    retryAndFollowUpInterceptor.isForWebSocket()));
 

 

 

这里RetryAndFollowUpInterceptor是第一个拦截器,它会依次调用前面添加拦截器的顺序

 

关注到intercept方法

@Override public Response intercept(Chain chain) throws IOException {
  Request request = chain.request();
  
  streamAllocation = new StreamAllocation(
      client.connectionPool(), createAddress(request.url()));
  
  int followUpCount = 0;
  Response priorResponse = null;
  while (true) {
    if (canceled) {
      streamAllocation.release();
      throw new IOException("Canceled");
    }
  
    Response response = null;
    boolean releaseConnection = true;
    try {
      response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, null, null);
      releaseConnection = false;
    } catch (RouteException e) {
      // The attempt to connect via a route failed. The request will not have been sent.
      if (!recover(e.getLastConnectException(), true, request)) throw e.getLastConnectException();
      releaseConnection = false;
      continue;
    } catch (IOException e) {
      // An attempt to communicate with a server failed. The request may have been sent.
      if (!recover(e, false, request)) throw e;
      releaseConnection = false;
      continue;
    } finally {
      // We're throwing an unchecked exception. Release any resources.
      if (releaseConnection) {
        streamAllocation.streamFailed(null);
        streamAllocation.release();
      }
    }
  
    // Attach the prior response if it exists. Such responses never have a body.
    if (priorResponse != null) {
      response = response.newBuilder()
          .priorResponse(priorResponse.newBuilder()
              .body(null)
              .build())
          .build();
    }
  
    Request followUp = followUpRequest(response);
  
    if (followUp == null) {
      if (!forWebSocket) {
        streamAllocation.release();
      }
      return response;
    }
  
    closeQuietly(response.body());
  
    if (++followUpCount > MAX_FOLLOW_UPS) {
      streamAllocation.release();
      throw new ProtocolException("Too many follow-up requests: " + followUpCount);
    }
  
    if (followUp.body() instanceof UnrepeatableRequestBody) {
      throw new HttpRetryException("Cannot retry streamed HTTP body", response.code());
    }
  
    if (!sameConnection(response, followUp.url())) {
      streamAllocation.release();
      streamAllocation = new StreamAllocation(
          client.connectionPool(), createAddress(followUp.url()));
    } else if (streamAllocation.stream() != null) {
      throw new IllegalStateException("Closing the body of " + response
          + " didn't close its backing stream. Bad interceptor?");
    }
  
    request = followUp;
    priorResponse = response;
  }
}

 

ConnectInterceptor的intercepter方法
@Override public Response intercept(Chain chain) throws IOException {
  RealInterceptorChain realChain = (RealInterceptorChain) chain;
  Request request = realChain.request();
  StreamAllocation streamAllocation = realChain.streamAllocation();
  
  // We need the network to satisfy this request. Possibly for validating a conditional GET.
  boolean doExtensiveHealthChecks = !request.method().equals("GET");
  HttpStream httpStream = streamAllocation.newStream(client, doExtensiveHealthChecks);
  RealConnection connection = streamAllocation.connection();
  
  return realChain.proceed(request, streamAllocation, httpStream, connection);
  }

 

这里我们关注这一句

HttpStream httpStream= streamAllocation.newStream(client,doExtensiveHealthChecks);

newStream()方法

public HttpStream newStream(OkHttpClient client, boolean doExtensiveHealthChecks) {
  int connectTimeout = client.connectTimeoutMillis();
  int readTimeout = client.readTimeoutMillis();
  int writeTimeout = client.writeTimeoutMillis();
  boolean connectionRetryEnabled = client.retryOnConnectionFailure();
  
  try {
    RealConnection resultConnection = findHealthyConnection(connectTimeout, readTimeout,
        writeTimeout, connectionRetryEnabled, doExtensiveHealthChecks);
  
    HttpStream resultStream;
    if (resultConnection.framedConnection != null) {
      resultStream = new Http2xStream(client, this, resultConnection.framedConnection);
    } else {
      resultConnection.socket().setSoTimeout(readTimeout);
      resultConnection.source.timeout().timeout(readTimeout, MILLISECONDS);
      resultConnection.sink.timeout().timeout(writeTimeout, MILLISECONDS);
      resultStream = new Http1xStream(
          client, this, resultConnection.source, resultConnection.sink);
    }
  
    synchronized (connectionPool) {
      stream = resultStream;
      return resultStream;
    }
  } catch (IOException e) {
    throw new RouteException(e);
  }
}

 

这里实际调用了Http1xStream实际上是说明http是使用的http1.1

resultStream= new Http1xStream(
    client, this, resultConnection.source, resultConnection.sink);

 

这里的resultConnection有点讲究

RealConnection resultConnection = findHealthyConnection(connectTimeout, readTimeout,
    writeTimeout, connectionRetryEnabled, doExtensiveHealthChecks);

 

详细源码

private RealConnection findHealthyConnection(int connectTimeout, int readTimeout,
    int writeTimeout, boolean connectionRetryEnabled, boolean doExtensiveHealthChecks)
    throws IOException {
  while (true) {
    RealConnection candidate = findConnection(connectTimeout, readTimeout, writeTimeout,
        connectionRetryEnabled);
  
    // If this is a brand new connection, we can skip the extensive health checks.
    synchronized (connectionPool) {
      if (candidate.successCount == 0) {
        return candidate;
      }
    }
  
    // Do a (potentially slow) check to confirm that the pooled connection is still good. If it
    // isn't, take it out of the pool and start again.
    if (!candidate.isHealthy(doExtensiveHealthChecks)) {
      noNewStreams();
      continue;
    }
  
    return candidate;
  }
}

 

紧接着它调用了findConnection()

private RealConnection findConnection(int connectTimeout, int readTimeout, int writeTimeout,
    boolean connectionRetryEnabled) throws IOException {
  Route selectedRoute;
  synchronized (connectionPool) {
    if (released) throw new IllegalStateException("released");
    if (stream != null) throw new IllegalStateException("stream != null");
    if (canceled) throw new IOException("Canceled");
  
    RealConnection allocatedConnection = this.connection;
    if (allocatedConnection != null && !allocatedConnection.noNewStreams) {
      return allocatedConnection;
    }
  
    // Attempt to get a connection from the pool.
    RealConnection pooledConnection = Internal.instance.get(connectionPool, address, this);
    if (pooledConnection != null) {
      this.connection = pooledConnection;
      return pooledConnection;
    }
  
    selectedRoute = route;
  }
  
  if (selectedRoute == null) {
    selectedRoute = routeSelector.next();
    synchronized (connectionPool) {
      route = selectedRoute;
      refusedStreamCount = 0;
    }
  }
  RealConnection newConnection = new RealConnection(selectedRoute);
  acquire(newConnection);
  
  synchronized (connectionPool) {
    Internal.instance.put(connectionPool, newConnection);
    this.connection = newConnection;
    if (canceled) throw new IOException("Canceled");
  }
  
  newConnection.connect(connectTimeout, readTimeout, writeTimeout, address.connectionSpecs(),
      connectionRetryEnabled);
  routeDatabase().connected(newConnection.route());
  
  return newConnection;
  }

 

 

建立连接

public void connect(int connectTimeout, int readTimeout, int writeTimeout,
    List<ConnectionSpec> connectionSpecs, boolean connectionRetryEnabled) {
  if (protocol != null) throw new IllegalStateException("already connected");
  
  RouteException routeException = null;
  ConnectionSpecSelector connectionSpecSelector = new ConnectionSpecSelector(connectionSpecs);
  
  if (route.address().sslSocketFactory() == null) {
    if (!connectionSpecs.contains(ConnectionSpec.CLEARTEXT)) {
      throw new RouteException(new UnknownServiceException(
          "CLEARTEXT communication not enabled for client"));
    }
    String host = route.address().url().host();
    if (!Platform.get().isCleartextTrafficPermitted(host)) {
      throw new RouteException(new UnknownServiceException(
          "CLEARTEXT communication to " + host + " not permitted by network security policy"));
    }
  }
  
  while (protocol == null) {
    try {
      if (route.requiresTunnel()) {
        buildTunneledConnection(connectTimeout, readTimeout, writeTimeout,
            connectionSpecSelector);
      } else {
        buildConnection(connectTimeout, readTimeout, writeTimeout, connectionSpecSelector);
      }
    } catch (IOException e) {
      closeQuietly(socket);
      closeQuietly(rawSocket);
      socket = null;
      rawSocket = null;
      source = null;
      sink = null;
      handshake = null;
      protocol = null;
  
      if (routeException == null) {
        routeException = new RouteException(e);
      } else {
        routeException.addConnectException(e);
      }
  
      if (!connectionRetryEnabled || !connectionSpecSelector.connectionFailed(e)) {
        throw routeException;
      }
    }
  }
}

 

看下一步buildTunneledConnection

private void buildTunneledConnection(int connectTimeout, int readTimeout, int writeTimeout,
    ConnectionSpecSelector connectionSpecSelector) throws IOException {
  Request tunnelRequest = createTunnelRequest();
  HttpUrl url = tunnelRequest.url();
  int attemptedConnections = 0;
  int maxAttempts = 21;
  while (true) {
    if (++attemptedConnections > maxAttempts) {
      throw new ProtocolException("Too many tunnel connections attempted: " + maxAttempts);
    }
  
    connectSocket(connectTimeout, readTimeout);
    tunnelRequest = createTunnel(readTimeout, writeTimeout, tunnelRequest, url);
  
    if (tunnelRequest == null) break; // Tunnel successfully created.
  
    // The proxy decided to close the connection after an auth challenge. We need to create a new
    // connection, but this time with the auth credentials.
    closeQuietly(rawSocket);
    rawSocket = null;
    sink = null;
    source = null;
  }
  
  establishProtocol(readTimeout, writeTimeout, connectionSpecSelector);
  }

 

这里的重点方法connectSocket(),实际上透露就是Socket连接.到这里已经建立连接,接下来解析,但是先看看最后一个拦截器CallServerInterceptor
@Override public Response intercept(Chain chain) throws IOException {
  HttpStream httpStream = ((RealInterceptorChain) chain).httpStream();
  StreamAllocation streamAllocation = ((RealInterceptorChain) chain).streamAllocation();
  Request request = chain.request();
  
  long sentRequestMillis = System.currentTimeMillis();
  httpStream.writeRequestHeaders(request);
  
  if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
    Sink requestBodyOut = httpStream.createRequestBody(request, request.body().contentLength());
    BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
    request.body().writeTo(bufferedRequestBody);
    bufferedRequestBody.close();
  }
  
  httpStream.finishRequest();
  
  Response response = httpStream.readResponseHeaders()
      .request(request)
      .handshake(streamAllocation.connection().handshake())
      .sentRequestAtMillis(sentRequestMillis)
      .receivedResponseAtMillis(System.currentTimeMillis())
      .build();
  
  if (!forWebSocket || response.code() != 101) {
    response = response.newBuilder()
        .body(httpStream.openResponseBody(response))
        .build();
  }
  
  if ("close".equalsIgnoreCase(response.request().header("Connection"))
      || "close".equalsIgnoreCase(response.header("Connection"))) {
    streamAllocation.noNewStreams();
  }
  
  int code = response.code();
  if ((code == 204 || code == 205) && response.body().contentLength() > 0) {
    throw new ProtocolException(
        "HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());
  }
  
  return response;
  }
 

很明显这里的HttpStream就是http1Xstream

调用 @Override public void writeRequestHeaders(Request request) throws IOException {
  String requestLine = RequestLine.get(
      request, streamAllocation.connection().route().proxy().type());
  writeRequest(request.headers(), requestLine);
}

这里解析Headers

public void writeRequest(Headers headers, String requestLine) throws IOException {
  if (state != STATE_IDLE) throw new IllegalStateException("state: " + state);
  sink.writeUtf8(requestLine).writeUtf8("\r\n");
  for (int i = 0, size = headers.size(); i < size; i++) {
    sink.writeUtf8(headers.name(i))
        .writeUtf8(": ")
        .writeUtf8(headers.value(i))
        .writeUtf8("\r\n");
  }
  sink.writeUtf8("\r\n");
  state = STATE_OPEN_REQUEST_BODY;
  }

 

 

这就是最后的response

Response response = httpStream.readResponseHeaders()
    .request(request)
    .handshake(streamAllocation.connection().handshake())
    .sentRequestAtMillis(sentRequestMillis)
    .receivedResponseAtMillis(System.currentTimeMillis())
    .build();

 

至此,一个大概的请求分析完毕。

建议:最好是自己动手跟一遍代码,“纸上得来终觉浅,绝知此事要躬行。”实践总会发现更多新东西。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值