责任链模式应用之Okhttp的拦截器机制

13 篇文章 0 订阅

责任链模式的概念

责任链模式定义如下:
Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request.Chain the receiving objects and pass the request along the chain until an object handles it.(翻一下:使多个对象都有机会处理请求,从而避免了请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理为止。)
用简单的类图表示如下:
在这里插入图片描述
从概念上和类图上可以推断责任链会带来最大的优点,就是将请求和处理分开,请求者完全不用care是谁处理,是谁在加工。模式的核心在于创建一条chain,而处理具体事务的是chain的节点ConcreteHandler。研究这个模式,okhttp的拦截器机制是很好的研究点。

OKhttp的拦截器机制

这里展示一下demo,简单输出一下url,demo只是为了演示用法,不具有实际应用性。

      OkHttpClient okHttpClient = new OkHttpClient.Builder()
        .addInterceptor(hostSelectionInterceptor)
        .addInterceptor(new Interceptor() {
          @Override
          public okhttp3.Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            System.out.println("request url intercept " + request.url().toString());
            return chain.proceed(request);
          }
        })
        .build();
    Request request = new Request.Builder().url("http://www.github.com/").build();
    Response response = okHttpClient.newCall(request).execute();

控制台会打印:“request url intercept http://www.github.com/”,request和interceptor解耦,request不用care intercept 怎么处理,只关心repose的内容。
这个具体实现原理到底是啥呢,这里不扒okhttp的运行原理,只讲重点部分。
OkhttpClient.newCall(request)返回的对象的类是RealCall,我们直接看这个类的execute方法,

    public Response execute() throws IOException {
        synchronized(this) {
            if (this.executed) {
                throw new IllegalStateException("Already Executed");
            }

            this.executed = true;
        }

        this.transmitter.timeoutEnter();
        this.transmitter.callStart();

        Response var1;
        try {
            this.client.dispatcher().executed(this);
            var1 = this.getResponseWithInterceptorChain();
        } finally {
            this.client.dispatcher().finished(this);
        }

        return var1;
    }

关键看this.getResponseWithInterceptorChain(),在这个方法里处理了拦截器机制的主要逻辑。


    Response getResponseWithInterceptorChain() throws IOException {
        List<Interceptor> interceptors = new ArrayList();
        interceptors.addAll(this.client.interceptors());
        interceptors.add(new RetryAndFollowUpInterceptor(this.client));
        interceptors.add(new BridgeInterceptor(this.client.cookieJar()));
        interceptors.add(new CacheInterceptor(this.client.internalCache()));
        interceptors.add(new ConnectInterceptor(this.client));
        if (!this.forWebSocket) {
            interceptors.addAll(this.client.networkInterceptors());
        }

        interceptors.add(new CallServerInterceptor(this.forWebSocket));
        Chain chain = new RealInterceptorChain(interceptors, this.transmitter, (Exchange)null, 0, this.originalRequest, this, this.client.connectTimeoutMillis(), this.client.readTimeoutMillis(), this.client.writeTimeoutMillis());
        boolean calledNoMoreExchanges = false;

        Response var5;
        try {
            Response response = chain.proceed(this.originalRequest);
            if (this.transmitter.isCanceled()) {
                Util.closeQuietly(response);
                throw new IOException("Canceled");
            }

            var5 = response;
        } catch (IOException var9) {
            calledNoMoreExchanges = true;
            throw this.transmitter.noMoreExchanges(var9);
        } finally {
            if (!calledNoMoreExchanges) {
                this.transmitter.noMoreExchanges((IOException)null);
            }

        }

        return var5;
    }

先创建了拦截器的数组interceptors,this.client.interceptors()返回的是我们自己定义的拦截器,经常使用的还有处理cookie的BridgeInterceptor,其他都是框架内置的拦截器。然后创建了链对象chain,类型是RealInterceptorChain,RealInterceptorChain的构造方法:

    public RealInterceptorChain(List<Interceptor> interceptors, Transmitter transmitter, @Nullable Exchange exchange, int index, Request request, Call call, int connectTimeout, int readTimeout, int writeTimeout) {
        this.interceptors = interceptors;
        this.transmitter = transmitter;
        this.exchange = exchange;
        this.index = index;
        this.request = request;
        this.call = call;
        this.connectTimeout = connectTimeout;
        this.readTimeout = readTimeout;
        this.writeTimeout = writeTimeout;
    }

chain保存interceptors数组,其他参数如transmitter,exchange 暂且不提,这里主要理解责任链模式。这个数组其实就是所以处理具体事务的节点。

最后调用chain.proceed方法。

    public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange) throws IOException {
        if (this.index >= this.interceptors.size()) {
            throw new AssertionError();
        } else {
            ++this.calls;
            if (this.exchange != null && !this.exchange.connection().supportsUrl(request.url())) {
                throw new IllegalStateException("network interceptor " + this.interceptors.get(this.index - 1) + " must retain the same host and port");
            } else if (this.exchange != null && this.calls > 1) {
                throw new IllegalStateException("network interceptor " + this.interceptors.get(this.index - 1) + " must call proceed() exactly once");
            } else {
                RealInterceptorChain next = new RealInterceptorChain(this.interceptors, transmitter, exchange, this.index + 1, request, this.call, this.connectTimeout, this.readTimeout, this.writeTimeout);
                Interceptor interceptor = (Interceptor)this.interceptors.get(this.index);
                Response response = interceptor.intercept(next);
                if (exchange != null && this.index + 1 < this.interceptors.size() && next.calls != 1) {
                    throw new IllegalStateException("network interceptor " + interceptor + " must call proceed() exactly once");
                } else if (response == null) {
                    throw new NullPointerException("interceptor " + interceptor + " returned null");
                } else if (response.body() == null) {
                    throw new IllegalStateException("interceptor " + interceptor + " returned a response with no body");
                } else {
                    return response;
                }
            }
        }
    }

传入request,还记得前面构造RealInterceptorChain对象,exchange对象是null,所以在proceed方法中,逻辑会走到else分支,就是获取下一个拦截器(下一个节点)来处理这个请求,调用拦截器的interceptos方法,传入新创建的节点。这里和标准的责任链不一样,第一个是节点处理顺序是用数组元素的顺序,第二个不同点每次调用下一个节点的时候,是重新创建的,没有一开始就把链创建好,但其思想是一样的,如果调用的是execute,那么拦截器的执行就在调用的线程,如果是enqueue,那么是在线程池创建的线程里,这个不详细说明,可以看源码,okhttp的执行流程还是很清晰的。最后返回的是response对象。此时我们可以画一个简单的类图。
在这里插入图片描述
在这里拦截器起这么一个作用,执行下一个节点的proceed方法或者直接返回响应的response,在执行前后给request或者response加工。在okhttp中直接返回response的拦截器就是CallServerInterceptor,可以看下这个拦截器的proceed方法,就是最终处理了request。下一篇文章实战下,分析下自带的BridgeInterceptor将cookie添加到request中。

总结

okhttp的拦截器机制是通过责任链模式来设计,虽然不是标准的责任链,但实现这个模式的主要思想。RealCall发起了请求,拦截器处理请求并调用下一个节点的处理,形成一条完美的chain,最后返回请求结果response

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值