为了彻底搞明白okhttp原理,仿照okhttp自研一个

业务上没发出一个request,使用AsyncCall包装起来,然后在网络分发器的作用下,执行具体的每一个Call,这些具体的Call会经过层层的拦截器,最终会调用到CallServiceInterceptor,这个对象里面有一个ConnectionPool,保存着每一个url对应的socket,最终处理的结果返回交给具体的每一个call,然后在回调到业务层

4.1 request
- public class Request {
-
-
- private Map<String, String> headers;
- private String method;
- private HttpUrl url;
- private RequestBody body;
-
- public Request(Builder builder) {
- this.url = builder.url;
- this.method = builder.method;
- this.headers = builder.headers;
- this.body = builder.body;
- }
-
- public String method() {
- return method;
- }
-
- public HttpUrl url() {
- return url;
- }
-
- public RequestBody body() {
- return body;
- }
-
- public Map<String, String> headers() {
- return headers;
- }
-
-
- public final static class Builder {
-
- HttpUrl url;
- Map<String, String> headers = new HashMap<>();
- String method;
-
- RequestBody body;
-
- public Builder url(String url) {
- try {
- this.url = new HttpUrl(url);
- return this;
- } catch (MalformedURLException e) {
- throw new IllegalStateException("Failed Http Url", e);
- }
- }
-
-
- public Builder addHeader(String name, String value) {
- headers.put(name, value);
- return this;
- }
-
-
- public Builder removeHeader(String name) {
- headers.remove(name);
- return this;
- }
-
- public Builder get() {
- method = "GET";
- return this;
- }
-
-
- public Builder post(RequestBody body) {
- this.body = body;
- method = "POST";
- return this;
- }
-
- public Request build() {
- if (url == null) {
- throw new IllegalStateException("url == null");
- }
- if (TextUtils.isEmpty(method)) {
- method = "GET";
- }
- return new Request(this);
- }
-
- }
- }
4.2 Response
- public class Response {
-
- int code;
- int contentLength = -1;
- Map<String, String> headers = new HashMap<>();
-
- String body;
- //保持连接
- boolean isKeepAlive;
-
- public Response() {
- }
-
- public Response(int code, int contentLength, Map<String, String> headers, String body,
- boolean isKeepAlive) {
- this.code = code;
- this.contentLength = contentLength;
- this.headers = headers;
- this.body = body;
- this.isKeepAlive = isKeepAlive;
- }
-
- public int getCode() {
- return code;
- }
-
- public int getContentLength() {
- return contentLength;
- }
-
- public Map<String, String> getHeaders() {
- return headers;
- }
-
- public String getBody() {
- return body;
- }
-
- public boolean isKeepAlive() {
- return isKeepAlive;
- }
- }
4.3 HttpUrl
- public class HttpUrl {
-
-
- String protocol;
- String host;
- String file;
- int port;
-
-
- public HttpUrl(String url) throws MalformedURLException {
- URL url1 = new URL(url);
- host = url1.getHost();
- file = url1.getFile();
- file = TextUtils.isEmpty(file) ? "/" : file;
- protocol = url1.getProtocol();
- port = url1.getPort();
- port = port == -1 ? url1.getDefaultPort() : port;
- }
-
- public String getProtocol() {
- return protocol;
- }
-
- public String getHost() {
- return host;
- }
-
- public String getFile() {
- return file;
- }
-
- public int getPort() {
- return port;
- }
- }
4.4 Call
- public class Call {
-
- Request request;
-
- HttpClient client;
-
- //是否执行过
- boolean executed;
-
- boolean cancel;
-
- public boolean isCancel() {
- return cancel;
- }
-
- public Request getRequest() {
- return request;
- }
-
- public Call(Request request, HttpClient client) {
- this.request = request;
- this.client = client;
- }
-
- public HttpClient getClient() {
- return client;
- }
-
- public void enqueue(Callback callback) {
- synchronized (this) {
- if (executed) {
- throw new IllegalStateException("已经执行过了,就不要执行");
- }
- executed = true;
- }
- //把任务交给调度器调度
- client.dispatcher().enqueue(new AsyncCall(callback));
- }
-
- /**
- * 是否取消
- */
- public void cancel() {
- cancel = true;
- }
-
- /**
- * 执行网络请求的线程
- */
- class AsyncCall implements Runnable {
-
- private Callback callback;
-
- public AsyncCall(Callback callback) {
- this.callback = callback;
- }
-
- @Override
- public void run() {
-
-
- //是否回调过
- boolean singaledCallbacked = false;
- try {
- //执行真正的请求
- Response response = getResponse();
- if (cancel) {
- singaledCallbacked = true;
- callback.onFailure(Call.this, new IOException("客户端主动执行了cancel"));
- } else {
- singaledCallbacked = true;
- callback.onResponse(Call.this, response);
- }
- } catch (Exception e) {
- // e.printStackTrace();
- if (!singaledCallbacked) {
- //如果没有回调过
- callback.onFailure(Call.this, e);
- }
- } finally {
- //将这个任务从调度器移除
- client.dispatcher().finished(this);
- }
- }
-
-
-
- public String host() {
- return request.url().getHost();
- }
- }
-
- /**
- * 这里是重点!!!
- * @return
- */
- private Response getResponse() throws Exception{
- //创建拦截器责任链
- List<Interceptor> interceptors = new ArrayList();
- //重试拦截器
- interceptors.add(new RetryInterceptor());
- //请求头拦截器
- interceptors.add(new HeaderInterceptor());
- //缓存拦截器
- interceptors.add(new CacheInterceptor());
- //连接拦截器
- interceptors.add(new ConnectionInterceptor());
- //通信拦截器
- interceptors.add(new CallServiceInterceptor());
- InterceptorChain chain = new InterceptorChain(interceptors, 0, this, null);
- return chain.process();
- }
- }
4.5 InterceptorChain
- public class InterceptorChain {
-
- List<Interceptor> interceptors;
- int index;
- Call call;
- HttpConnection httpConnection;
-
-
- public InterceptorChain(List<Interceptor> interceptors, int index, Call call, HttpConnection connection) {
- this.interceptors = interceptors;
- this.index = index;
- this.call = call;
- this.httpConnection = connection;
- }
-
- public Response process(HttpConnection httpConnection) throws IOException{
-
- this.httpConnection = httpConnection;
- return process();
- }
-
- public Response process() throws IOException {
- if (index >= interceptors.size()) throw new IOException("Interceptor China index out max length");
- //获得拦截器 去执行
- Interceptor interceptor = interceptors.get(index);
- InterceptorChain next = new InterceptorChain(interceptors, index + 1, call, httpConnection);
- Response response = interceptor.intercept(next);
-
- return response;
- }
- }
4.6 Interceptor
- public interface Interceptor {
-
- Response intercept(InterceptorChain chain) throws IOException;
- }
4.7 ConnectionPool
- public class ConnectionPool {
-
- private static final String TAG = "ConnectionPool";
- private static final boolean DEBUG = BuildConfig.DEBUG;
-
-
- private final long keepAlive;
-
-
- private boolean cleanrunning;
-
- private Deque<HttpConnection> connections = new ArrayDeque<>();
-
- public ConnectionPool() {
- this(1, TimeUnit.MINUTES);
- }
-
- public ConnectionPool(long keepAlive, TimeUnit unit) {
-
- this.keepAlive = unit.toMillis(keepAlive);
- }
-
-
- private Runnable cleanupRunable = new Runnable() {
- @Override
- public void run() {
-
- while (true) {
- long waitDuration = cleanup(System.currentTimeMillis());
- if (waitDuration == -1) {
- return;
- }
- if (waitDuration > 0) {
- synchronized (ConnectionPool.this) {
- try {
- ConnectionPool.this.wait(waitDuration);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- }
- }
- };
-
- private long cleanup(long currentTimeMillis) {
- long longgetIdleDuration = -1;
- synchronized (this) {
-
- Iterator<HttpConnection> iterator = connections.iterator();
- while (iterator.hasNext()) {
- HttpConnection connection = iterator.next();
- long idleDuration = currentTimeMillis - connection.getLastUseTime();
- //超过了最大允许闲置时间
- if (idleDuration > keepAlive) {
- if (DEBUG) Log.d(TAG, "ConnectionPool cleanup: " + "超出闲置时间,移除连接池");
- iterator.remove();
- connection.close();
- continue;
- }
- //没有超过闲置时间
- //记录 最长的闲置时间
- if (longgetIdleDuration < idleDuration) {
- longgetIdleDuration = idleDuration;
- }
- }
- //假如keepAlive是10s
- //
- if (longgetIdleDuration >= 0) {
- return keepAlive - longgetIdleDuration;
- }
- //连接池中没有连接
- cleanrunning = false;
- return longgetIdleDuration;
- }
- }
-
- private static final Executor executer = new ThreadPoolExecutor(0, Integer.MAX_VALUE,
- 60, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), new ThreadFactory() {
- @Override
- public Thread newThread(Runnable r) {
- Thread thread = new Thread(r, "Connection Pool");
- thread.setDaemon(true);//设置为守护线程,可以理解为跟进程同样的生命周期
- return thread;
- }
- });
-
-
- public void put(HttpConnection httpConnection) {
- //如果没有执行清理线程
- if (!cleanrunning) {
- cleanrunning = true;
- executer.execute(cleanupRunable);
- }
- connections.add(httpConnection);
- }
-
-
- public synchronized HttpConnection get(String host, int port) {
- Iterator<HttpConnection> iterator = connections.iterator();
-
- while (iterator.hasNext()) {
- HttpConnection connection = iterator.next();
- //如果查找到连接池始终在相同的host和port
- if (connection.isSameAddress(host, port)) {
- iterator.remove();
- return connection;
- }
- }
- return null;
- }
-
-
- }
4.8 CallServiceInterceptor
- public class CallServiceInterceptor implements Interceptor {
-
- private static final String TAG = "CallServiceInterceptor";
- private static final boolean DEBUG = BuildConfig.DEBUG;
-
- @Override
- public Response intercept(InterceptorChain chain) throws IOException {
- if (DEBUG) Log.d(TAG, "CallServiceInterceptor intercept: " + "通信拦截器");
- HttpConnection connection = chain.httpConnection;
- HttpCode httpCode = new HttpCode();
- InputStream inputStream = connection.call(httpCode);
- String statusLine = httpCode.readLine(inputStream);
- Map<String, String> headers = httpCode.readHeaders(inputStream);
- int contentLength = -1;
- if (headers.containsKey("Content-Length")) {
- //如果有content-length,代表可以拿到响应体的字节长度
- contentLength = Integer.valueOf(headers.get("Content-Length"));
- }
- boolean isChunked = false;
- if (headers.containsKey("Transfer-Encoding")) {
- //如果有有Transfer-Encoding,表示是分块编码,此时没有响应体的长度
- isChunked = headers.get("Transfer-Encoding").equalsIgnoreCase("chunked");
- }
-
- String body = null;
- if (contentLength > 0) {
- byte[] bytes = httpCode.readBytes(inputStream, contentLength);
- body = new String(bytes);
- } else if (isChunked) {
- body = httpCode.readChunked(inputStream);
- }
-
- String[] status = statusLine.split(" ");
-
- boolean isKeepAlive = false;
-
- if (headers.containsKey("Connection")) {
- isKeepAlive = headers.get("Connection").equalsIgnoreCase("Keep-Alive");
- }
- connection.updateLastUseTime();
- return new Response(Integer.valueOf(status[1]), contentLength, headers, body,isKeepAlive);
- }
- }