Okhttp3.11.0框架原理分析

32 阅读4分钟

1.OkHttp用法

(1).Get请求 new OkHttpClient ,构造Request对象,调用newCall方法获取Call对象,通过call#enqueue或者excute来提交请求。

String url = "http://wwww.baidu.com";
OkHttpClient okHttpClient = new OkHttpClient();
          //POST提交表单
        FormBody formBody = new FormBody.Builder()
                .add("username", "your_username")
                .add("password", "your_password")
                .build();
        Request request1=new Request.Builder().url("url").post(formBody).build();
        //POST提交JSON
        MediaType mediaType = MediaType.get("application/json; charset=utf-8");
        String jsonBody = "{\"key\":\"value\"}";
        RequestBody body = RequestBody.create(mediaType,jsonBody);
        Request request2=new Request.Builder().url("").post(body).build();

Call call = okHttpClient.newCall(request1);
call.enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
        Log.d(TAG, "onFailure: ");
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        Log.d(TAG, "onResponse: " + response.body().string());
    }
});

(2).Post请求 在构建Request对象的时候,需要多构造一个RequestBody对象,同时指定MediaType用于描述请求/响应body的内容类型 Post提交String

MediaType mediaType = MediaType.parse("text/x-markdown; charset=utf-8");
String requestBody = "I am Jdqm.";
Request request = new Request.Builder()
        .url("https://api.github.com/markdown/raw")
        .post(RequestBody.create(mediaType, requestBody))
        .build();
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.newCall(request).enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
        Log.d(TAG, "onFailure: " + e.getMessage());
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        Log.d(TAG, response.protocol() + " " +response.code() + " " + response.message());
        Headers headers = response.headers();
        for (int i = 0; i < headers.size(); i++) {
            Log.d(TAG, headers.name(i) + ":" + headers.value(i));
        }
        Log.d(TAG, "onResponse: " + response.body().string());
    }
});

Post提交流

RequestBody requestBody = new RequestBody() {
    @Nullable
    @Override
    public MediaType contentType() {
        return MediaType.parse("text/x-markdown; charset=utf-8");
    }

    @Override
    public void writeTo(BufferedSink sink) throws IOException {
        sink.writeUtf8("I am Jdqm.");
    }
};

Request request = new Request.Builder()
        .url("https://api.github.com/markdown/raw")
        .post(requestBody)
        .build();
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.newCall(request).enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
        Log.d(TAG, "onFailure: " + e.getMessage());
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        Log.d(TAG, response.protocol() + " " +response.code() + " " + response.message());
        Headers headers = response.headers();
        for (int i = 0; i < headers.size(); i++) {
            Log.d(TAG, headers.name(i) + ":" + headers.value(i));
        }
        Log.d(TAG, "onResponse: " + response.body().string());
    }
});

Post提交文件

MediaType mediaType = MediaType.parse("text/x-markdown; charset=utf-8");
OkHttpClient okHttpClient = new OkHttpClient();
File file = new File("test.md");
Request request = new Request.Builder()
        .url("https://api.github.com/markdown/raw")
        .post(RequestBody.create(mediaType, file))
        .build();
okHttpClient.newCall(request).enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
        Log.d(TAG, "onFailure: " + e.getMessage());
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        Log.d(TAG, response.protocol() + " " +response.code() + " " + response.message());
        Headers headers = response.headers();
        for (int i = 0; i < headers.size(); i++) {
            Log.d(TAG, headers.name(i) + ":" + headers.value(i));
        }
        Log.d(TAG, "onResponse: " + response.body().string());
    }
});

Post提交表单

HttpClient okHttpClient = new OkHttpClient();
RequestBody requestBody = new FormBody.Builder()
        .add("search", "Jurassic Park")
        .build();
Request request = new Request.Builder()
        .url("https://en.wikipedia.org/w/index.php")
        .post(requestBody)
        .build();

okHttpClient.newCall(request).enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
        Log.d(TAG, "onFailure: " + e.getMessage());
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        Log.d(TAG, response.protocol() + " " +response.code() + " " + response.message());
        Headers headers = response.headers();
        for (int i = 0; i < headers.size(); i++) {
            Log.d(TAG, headers.name(i) + ":" + headers.value(i));
        }
        Log.d(TAG, "onResponse: " + response.body().string());
    }
});

Post提交分块请求

private static final String IMGUR_CLIENT_ID = "...";
private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");

private void postMultipartBody() {
    OkHttpClient client = new OkHttpClient();


    // Use the imgur image upload API as documented at https://api.imgur.com/endpoints/image
    MultipartBody body = new MultipartBody.Builder("AaB03x")
            .setType(MultipartBody.FORM)
            .addPart(
                    Headers.of("Content-Disposition", "form-data; name=\"title\""),
                    RequestBody.create(null, "Square Logo"))
            .addPart(
                    Headers.of("Content-Disposition", "form-data; name=\"image\""),
                    RequestBody.create(MEDIA_TYPE_PNG, new File("website/static/logo-square.png")))
            .build();

    Request request = new Request.Builder()
            .header("Authorization", "Client-ID " + IMGUR_CLIENT_ID)
            .url("https://api.imgur.com/3/image")
            .post(body)
            .build();

    Call call = client.newCall(request);
    call.enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {

        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {
            System.out.println(response.body().string());

        }

    });
}

2.OkHttp原理

(2.1).初步流程图

eff4d373e7e0a05fb515b1639ada95f.jpg

d5257a27653fd67774db4ed837d9ce7.jpg

(2.2). OkHttp.newCall()流程分析
//基本使用
 OkHttpClient okHttpClient=new OkHttpClient().newBuilder().build();
        Request request=new Request.Builder().build();
        Call realCall= okHttpClient.newCall(request);
        realCall.enqueue(new Callback() { 
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {

            }
        });

 static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    // Safely publish the Call instance to the EventListener.
    RealCall call = new RealCall(client, originalRequest, forWebSocket); //实例化一个RealCall对象
    call.eventListener = client.eventListenerFactory().create(call);
    return call;
  }
 //RealCall构造函数
 private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    this.client = client;
    this.originalRequest = originalRequest; //初始化Request
    this.forWebSocket = forWebSocket;
    //初始化重试(重定向)拦截器
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
  }
2.3.enqueue流程分析
//RealCall中
 public void enqueue(Callback responseCallback) {
   //调用Dispatcher把AsyncCall加入队列
    client.dispatcher().enqueue(new AsyncCall(responseCallback)); 
  }

//Dispatcher中
  synchronized void enqueue(AsyncCall call) {
    //如果请求数小于64且同一域名请求小于5个,就把AsyncCall加入runningAsyncCalls队列,然后启动线程池执行,否则就把AsyncCall放入readAsyncCalls队列。
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }
//线程池创建
  public synchronized ExecutorService executorService() {
    if (executorService == null) {
      executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
          new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;
  }

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

  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) {
          Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
        } else {
          eventListener.callFailed(RealCall.this, e);
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        client.dispatcher().finished(this); 
      }
    }
  }
 //把请求队列从runningAsyncCalls中移除,
 void finished(AsyncCall call) {
    finished(runningAsyncCalls, call, true);
  }

 private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
    int runningCallsCount;
    Runnable idleCallback;
    synchronized (this) {
     //把AsyncCall从runningAsyncCalsl中移除
      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();
    }
  }

//然后遍历readyAsyncCalls队列,取出AysncCall加入到runningAsyncs队列,启动线程池立即执行。
 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.
    }
  }
2.5.getResponseWithInterceptorChain()流程分析

image.png

 Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());//自定义拦截器
/* 重试拦截器,判断用户是否取消了请求,在获得结果之后,会根据响应码判断是否需要重定向*/
    interceptors.add(retryAndFollowUpInterceptor);
/* 桥接拦截器,负责在http协议中加入必备字段如:host:192.168..0.1:8080,accept encodeing:gzip,connection:keep alive ,在获得结果之后,调用保存cookie接口并解析Gzip数据.*/
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
/*发起http请求的时候,会尝试读取缓存的响应数据,如果缓存存在有效数据,并满足缓存策略,则直接
返回缓存的数据,避免再次进行网络请求,如果不存在,会生成一个缓存策略,根据缓存策略指示,是否需要网络请求 */
    interceptors.add(new CacheInterceptor(client.internalCache()));
/*负责建立一个新的tcp/ip连接,并获得对应的socket流*/
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {
      interceptors.addAll(client.networkInterceptors());
    }
/*利用得到的socket.getOutputStream 向服务器发送Http请求,解析读取的响应数据,并将数据封装成response对象返回.*/
    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);
  }
2.6.Interceptor接口
public interface Interceptor {
  Response intercept(Chain chain) ;
  interface Chain {
    Request request();
    Response proceed(Request request) ;
}

2.7.RealInterceptors实现类
public final class RealInterceptorChain implements Interceptor.Chain {

     public RealInterceptorChain(List<Interceptor> interceptors, int index, Request request){
             this.interceptors = interceptors;
             this.index = index; 
             this.request = request;
     }
     public Response proceed(Request request){
          //index+1,可以在RealInterceptorChain中调用下一个Interceptor
          RealInterceptorChain next = new RealInterceptorChain(interceptors,  index + 1, request);
          Interceptor interceptor = interceptors.get(index);//得到当前责任人
          Response response = interceptor.intercept(next);
          return    response;    
     }
}