okhttp_架构篇

前言: okhttp采用责任链设计模式 对网络请求进行分层处理,这样使得代码更加的清晰简洁,

责任链:

责任链模式是一种设计模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,
直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,
这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。

本文稍后会再详细阐述其责任链的形成

okhhtp是个网络框架,那解决的问题自然是发出网络请求,接受网络响应,那他是如何开展呢

官网给出的实例是:
  private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
Request request = new Request.Builder()
    .url("https://publicobject.com/helloworld.txt")
    .build();

try (Response response = client.newCall(request).execute()) {
  if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

  Headers responseHeaders = response.headers();
  for (int i = 0; i < responseHeaders.size(); i++) {
    System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
  }

  System.out.println(response.body().string());
 }
 }  

也就是说

我们需要
(1)先声明一个request,在request中放入我们的请求地址和请求体,
(2)我们在利用request生成一个call(这个call完成了我们真正进行网络请求前所有准备)
(3)用我们生成的call实例,进行网络请求(同步或者是异步请求)

接下来我们根据上述的步骤一步步的对okhhtp从请求到响应进行解析

一、request

这是一个存放用户请求网络的方式,如url,请求头,请求体,请求方法,以及标识tag(这是用户对该请求的标识,为了取消时请求时可以按照tag来取消请求)
实现方式是采用的是构造模式 如下
Request request = new Request.Builder()
            .url("")//请求的url
            .addHeader("","")
            .header("","")
            .get()//设置请求的方法,还有post()等等 如果要设置请求体调用 public Builder method(String method, @Nullable RequestBody body){}方法
            .cacheControl(new CacheControl(....))//设置该请求的缓存请求头
            .tag("tag")//设置标志位
            .build();

二、Call
该类是okhhtp的核心类,该类实现发出请求,接受响应

我们首先分析call实例的生成再分析call的实例发出请求,接受响应

(1)生成实例

我们首先看接口call
    public interface Call extends Cloneable {

  Request request();
//同步请求 只有call类才有execute方法这也就是上面我所说的,要想实现网络请求先生成request再生成call
  Response execute() throws IOException;
//异步请求
  void enqueue(Callback responseCallback);
//取消请求
  void cancel();
  //是否在执行请求
  boolean isExecuted();
//是否已经取消
  boolean isCanceled();
//克隆
  Call clone();
    //注意这个类是生成call实例的工厂类,上面我们看到的okhttpclient就是该接口的实例
  interface Factory {
    Call newCall(Request request);
  }
}

如下:
    public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {}
我们可以看到OkHttpClient集成了Call.Factory,所以他可以生成call的实例

我们来看OkHttpClient的newcall()方法
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}

在看RealCall的newRealCall方法,其实这里我们应该已经知道call实例就是这个realcall

  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;
 }

看到这就验证上述,realcall就是真正的call实例,call.eventListener是网络请求监听类,用来监听,网络请求和响应的各个事件,如发出请求头,发出请求头,响应请求头等等
接下来我们来追踪网络请求,首先从RealCall的execute()方法开始,方法如下

  @Override public Response execute() throws IOException {
synchronized (this) {
  if (executed) throw new IllegalStateException("Already Executed");
    //executed默认是false 也就是说对于一个网络请求不能执行2次以及以上否则抛出异常
  executed = true;
}
//设置堆栈追踪信息,显示log
captureCallStackTrace();
//回调事件监听,call开始
eventListener.callStart(this);
try {
//client.dispatcher()获取Dispatcher实例,Dispatcher是存储正在执行的请求(方便取消网络请求),以及安排多个异步请求的执行策略(同时存储)
//该行代码就是存储该网络请求
  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);
}
 }

接下来分析getResponseWithInterceptorChain()方法

 Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
//这个方法是okhttp网络框架实现的精髓,即是:责任链模式
//构造拦截器存储集合
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) {
    //设置我们自己设置的网络拦截器,在这里我们应该稍微理解一点okhttp设置网络拦截器和应用拦截器的区别了吧
  interceptors.addAll(client.networkInterceptors());
}
//拦截器的最后一个环节,实现连接服务器
interceptors.add(new CallServerInterceptor(forWebSocket));
//初始化拦截链 
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
    originalRequest, this, eventListener, client.connectTimeoutMillis(),
    client.readTimeoutMillis(), client.writeTimeoutMillis());
//获取网络响应
return chain.proceed(originalRequest);

}

接下来我们分析RealInterceptorChain的proceed方法

@Override public Response proceed(Request request) throws IOException {
return proceed(request, streamAllocation, httpCodec, connection);
 }

//看来这只是个重载方法,我们继续往下看,下面是proceed方法的真正实现

public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
  RealConnection connection) throws IOException {
//index获取拦截器的位置信息,所以不能大于拦截器的总和
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.获取下一个拦截器index在getResponseWithInterceptorChain()方法中已经初始化为0
//这里在index+1意味着递归下一次拦截器的时候为当前基础加1
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
    connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
    writeTimeout);
//获取第一个拦截器
Interceptor interceptor = interceptors.get(index);
//调用拦截器的intercept(next)方法开始递归,知道获取最后一个拦截器的response
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;

}

这个我们分析下是如果实现递归的:分析递归我们需要首先分析拦截器的接口Interceptor

    public interface Interceptor {
//注意该抽象方法
  Response intercept(Chain chain) throws IOException;

  interface Chain {
    Request request();
    //获取网络响应的方法
    Response proceed(Request request) throws IOException;

    @Nullable Connection connection();

    Call call();

    int connectTimeoutMillis();

    Chain withConnectTimeout(int timeout, TimeUnit unit);

    int readTimeoutMillis();

    Chain withReadTimeout(int timeout, TimeUnit unit);

    int writeTimeoutMillis();

    Chain withWriteTimeout(int timeout, TimeUnit unit);
  }
}

注意拦截器接口只有一个必须要实现的抽象方法是Response intercept(Chain chain) throws IOException;
也就是说我们获取拦截链,但是必须返回一个网络响应response,但是拦截链中只有Response proceed(Request request) throws IOException;才可以获取response,
换句话说也就是每个拦截器的intercept方法必定会调用Chain的proceed方法,而proceed方法又会调用

// 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);

也就是说所有的拦截器都是在interceptor.intercept(next)卡住(不是真正意义上的卡),知道获取最后一个拦截器的response,然后再一次回调,直达最开始的getResponseWithInterceptorChain() 获取response

图解如下:

架构图解

以上就是okhhtp的大概框架,但是okhttp具体的网络请求是使用 Okio库实现的,但是okio又是包装了Socket实现网络通信,

猜你喜欢

转载自blog.csdn.net/wkk_ly/article/details/81004920