okhttp 原理笔记三:RealCall

RealCall 是哪里来的呢?故事的开始是从下面揭开的:

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

            }

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

            }
        });

这里,我们通过 okhttpclient 通过newCall 方法,返回了一个对象,然后,调用这个对象的enqueue方法,并且传了一个Callback 接口对象等待结果的回调。 然后,我们先看看这个newCall方法返回的是什么

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

 这个 newCall 是被重写了,我们看下是重写谁的方法

public interface Call extends Cloneable {
   //省略代码
  interface Factory {
    Call newCall(Request request);
  }
}

 这个其实是Call接口中内置的工厂接口,也就是说,okhttpclient 实现了 Call中内置的工厂接口,重写了接口里的 newCall 方法

public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {

它返回的是一个Call 类型的对象, 同时,这个对象是由RealCall 的newRealCall 方法返回的。我们看下这个RealCall 的实现

final class RealCall implements Call {

       它也实现了Call 接口,那么这个Call 对象的 enqueue 方法呢?我们看下

public interface Call extends Cloneable {
  void enqueue(Callback responseCallback);

        也是Call 接口的方法,留待子类实现,然后通过接口被调用。

       如此一来,目前知道的是:

                newCall 方法 是 Call.Factory  接口的方法,okhttpclient 通过实现Call.Factory接口,把 RealCall 搞出来。

                enqueue 方法是 Call 接口的方法,RealCall 通过实现Call 接口,重写了enqueue 方法。

       

我们看看RealCall 主要做了什么东西

public class RealCall {
    //用来调用触发请求,它里面有个 dispatcher ,dispatcher 用来处理请求队列
    final OkHttpClient client;

    /**
     * There is a cycle between the {@link Call} and {@link Transmitter} that makes this awkward.
     * This is set after immediately after creating the call instance.
     */
//用来控制连接,监听连接,请求的状态等
    private Transmitter transmitter;

    /** The application's original request unadulterated by redirects or auth headers. */
//开发者传进来的原始请求体,里面有请求的地址url,端口port,入参 body等一堆信息
    final Request originalRequest;
    //标记是啥请求? 一般是false
    final boolean forWebSocket;

    // Guarded by this.
//标记当前请求RealCall的执行状态,如果该值为true, 那么再去执行请求的时候,就会抛异常
    private boolean executed;

    /**
     这个构造方法私有化了,也就是说RealCall 不能直接new出来,所以,才有下面静态方法

     */
    private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
        this.client = client;
        this.originalRequest = originalRequest;
        this.forWebSocket = forWebSocket;
    }

    /**
     这个方法接收了3个参数,分别是客户端,原始请求体,用来标记socket类型的变量,不过这个标记一般都是false的
     这个RealCall被new出来之后,传给了Transmitter ,Transmitter  new出来后,又放到了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.transmitter = new Transmitter(client, call);
        return call;
    }


    @Override public Request request() {
        return originalRequest;
    }


    /**
     * 1、先判断call的执行状态,如果重复执行就抛个异常
     * 2、初始化 transmitter 的设置,设置超时机制,就是请求之前要设置好超时时间,以及反馈请求开始事件
     * 3、通过客户端持有的 dispatcher,调用它的执行方法,触发下一步操作
     * 4、就返回请求结果了
     * 最后必须执行的一步:结束请求这个请求的操作,不管请求的结果是怎样,包括在请求队列里移除
     * @return
     * @throws IOException
     */
    @Override public Response execute() throws IOException {
        synchronized (this) {
            if (executed) throw new IllegalStateException("Already Executed");
            executed = true;
        }
        transmitter.timeoutEnter();
        transmitter.callStart();
        try {
            client.dispatcher().executed(this);
            return getResponseWithInterceptorChain();
        } finally {
            client.dispatcher().finished(this);
        }
    }

    /**
     * 这个跟上面的 execute 不同在于,这个是异步的,所以,你会发现,需要穿入一个 Callback,用来回调结果给开发者
     * 1、先判断call的执行状态,如果重复执行就抛个异常
     * 2、transmitter 反馈请求开始事件
     * 3、通过客户端持有的 dispatcher,调用它的执行方法,触发下一步操作,Callback是放在 AsyncCall 里,再将AsyncCall传入 dispatcher
     * @param responseCallback
     */
    @Override public void enqueue(Callback responseCallback) {
        synchronized (this) {
            if (executed) throw new IllegalStateException("Already Executed");
            executed = true;
        }
        transmitter.callStart();
        client.dispatcher().enqueue(new AsyncCall(responseCallback));
    }

    /**
     * 取消请求
     */
    @Override public void cancel() {
        transmitter.cancel();
    }

    /**
     * 获取超时策略
     * @return
     */
    @Override public Timeout timeout() {
        return transmitter.timeout();
    }

    /**
     * 当前call的执行状态
     * @return
     */
    @Override public synchronized boolean isExecuted() {
        return executed;
    }

    /**
     * call的取消状态
     * @return
     */
    @Override public boolean isCanceled() {
        return transmitter.isCanceled();
    }

    /**
     * 这个就是复制的作用,将当前的call重新弄个拷贝出来,可以用来发多一次请求
     * @return
     */
    @SuppressWarnings("CloneDoesntCallSuperClone") // We are a final type & this saves clearing state.
    @Override public RealCall clone() {
        return RealCall.newRealCall(client, originalRequest, forWebSocket);
    }

    /**
     * 这个就厉害了,这个 AsyncCall 继承的类,意味着它是一个线程,因为 NamedRunnable 实现了Runnable接口
     * 所以大家把它当做是一个线程就好了,既然是线程,我们只要关注它的run方法就好了,但是,在 AsyncCall 里看不到run方法,翻看 NamedRunnable
     * 就发现,原来 NamedRunnable 的run会调用 AsyncCall 的execute 方法
     * 所以,我们要留意下 execute 做了什么
     *
     */
    final class AsyncCall extends NamedRunnable {
        /**
         * 就是请求的回调接口
         */
        private final Callback responseCallback;
        /**
         * 用来存储当前请求的主机数,一般用于多线程的判断,因为它是原子性的,数据比较准确,线程安全
         * volatile 关键字 加上 Unsafe 的帮助,使得它线程安全
         */
        private volatile AtomicInteger callsPerHost = new AtomicInteger(0);

        AsyncCall(Callback responseCallback) {
            super("OkHttp %s", redactedUrl());
            this.responseCallback = responseCallback;
        }

        AtomicInteger callsPerHost() {
            return callsPerHost;
        }

        void reuseCallsPerHostFrom(AsyncCall other) {
            this.callsPerHost = other.callsPerHost;
        }

        /**
         * 请求的服务器的地址
         * @return
         */
        String host() {
            return originalRequest.url().host();
        }

        /**
         * 请求体
         * @return
         */
        Request request() {
            return originalRequest;
        }

        RealCall get() {
            return RealCall.this;
        }

        /**
         * Attempt to enqueue this async call on {@code executorService}. This will attempt to clean up
         * if the executor has been shut down by reporting the call as failed.
         *
         * 机器翻译:尝试在executorService上将此异步调用加入队列。如果执行程序已通过将调用报告为失败而关闭,这将尝试进行清理。
         *
         * 在上面提到的 enqueue 方法中,这个方法最终就是会走到这里来,通过 ExecutorService线程池进行启动线程
         * 当启动线程后,就是意味着 AsyncCall 的 execute 方法被调用了,因为刚说了继承自线程,execute 方法在run 里面
         *
         * 在执行线程后,同时会伴随一个捕捉线程池拒绝服务的异常,为啥呢?因为这个是防止线程不被执行时的操作,当线程别拒绝了,就会走
         * 回调 onFailure 了,以及  transmitter 也做了一些列的连接相关的操作
         *
         * 最后一步,对执行结果进行判断,如果线程不成功,则客户端通过自身的 dispatcher 结束这个call的运行,请求队列里移除这个call
         *
         * @param executorService
         */
        void executeOn(ExecutorService executorService) {
            assert (!Thread.holdsLock(client.dispatcher()));
            boolean success = false;
            try {
                executorService.execute(this);
                success = true;
            } catch (RejectedExecutionException e) {
                InterruptedIOException ioException = new InterruptedIOException("executor rejected");
                ioException.initCause(e);
                transmitter.noMoreExchanges(ioException);
                responseCallback.onFailure(RealCall.this, ioException);
            } finally {
                if (!success) {
                    client.dispatcher().finished(this); // This call is no longer running!
                }
            }
        }

        /**
         * 线程启动的时候,走这里
         * 1、这里也有个transmitter的超时设置,刚才在同步请求那里也有
         * 2、启动拦截器链了
         * 3、设置了标志位,处理回调二次调用的异常
         * 4、不管怎样,最后一步,请求结束后都清除请求
         */
        @Override protected void execute() {
            boolean signalledCallback = false;
            transmitter.timeoutEnter();
            try {
                Response response = getResponseWithInterceptorChain();
                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);
                }
            } catch (Throwable t) {
                cancel();
                if (!signalledCallback) {
                    IOException canceledException = new IOException("canceled due to " + t);
                    canceledException.addSuppressed(t);
                    responseCallback.onFailure(RealCall.this, canceledException);
                }
                throw t;
            } finally {
                client.dispatcher().finished(this);
            }
        }
    }

    /**
     * Returns a string that describes this call. Doesn't include a full URL as that might contain
     * sensitive information.
     */
    String toLoggableString() {
        return (isCanceled() ? "canceled " : "")
                + (forWebSocket ? "web socket" : "call")
                + " to " + redactedUrl();
    }

    String redactedUrl() {
        return originalRequest.url().redact();
    }

    /**
     * 这里是拦截器的配置相关
     * 1、如果开发者另外配置了应用拦截器,就将这类拦截器放入集合中
     * 2、依次添加 RetryAndFollowUpInterceptor ,BridgeInterceptor ,CacheInterceptor ,ConnectInterceptor 4个拦截器
     * 3、如果不是 forWebSocket ,就要把开发者配置的网络拦截器也要放入集合中
     * 4、添加  CallServerInterceptor 拦截器
     * 5、构建一个拦截器链,拦截器链上有拦截器的信息,请求体,读、写、连接超时,transmitter 等东西。
     * 6、拦截器链开始处理,返回结果就是 Response 了
     * @return
     * @throws IOException
     */
    Response getResponseWithInterceptorChain() throws IOException {
        // Build a full stack of interceptors.
        List<Interceptor> interceptors = new ArrayList<>();
        interceptors.addAll(client.interceptors());
        interceptors.add(new RetryAndFollowUpInterceptor(client));
        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, transmitter, null, 0,
                originalRequest, this, client.connectTimeoutMillis(),
                client.readTimeoutMillis(), client.writeTimeoutMillis());

        boolean calledNoMoreExchanges = false;
        try {
            Response response = chain.proceed(originalRequest);
            if (transmitter.isCanceled()) {
                closeQuietly(response);
                throw new IOException("Canceled");
            }
            return response;
        } catch (IOException e) {
            calledNoMoreExchanges = true;
            throw transmitter.noMoreExchanges(e);
        } finally {
            if (!calledNoMoreExchanges) {
                transmitter.noMoreExchanges(null);
            }
        }
    }
}

           我在代码里做了一些注释,方便认识。

            但总的来说,RealCall主要做了以下:

                1、接收开发者传进来的请求信息,这些请求信息包括请求的地址,提交的参数body,okp客户端等信息

                2、它内置了一个线程的实现,所以,请求都是在线程里面处理的

                3、里面分别有同步请求,异步请求两个逻辑处理,其中异步请求是通过 dispatcher 分配的

                4、配置了拦截器,并且开始向拦截器提交请求体

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值