责任链模式 应用

责任链模式,对象行为模式,每一个对象对其下家引用,形成一条责任链,业务请求在链上传递,直到某一条件形成,责任承担者处理后 结束。标准的责任链是将只有链上的某一个对象对请求进行直接处理,然而实际应用中,往往是链上的多个责任对象对请求处理进行一次预处理,这样一来可以实现多个应用场景,如过滤,日志,访问控制等。从这种角度上看,类似于AOP的模型。

责任链 简单结构

每个承担者 引用下一个承担者的对象。形成一条处理链。

134833_seeK_2834932.png

介绍几个应用场景

1、 netty 4

1)pipeline的构造

channel中封装了 一个 Pipeline,

DefaultChannelPipeline   //封装了一个条handlerContext的 责任链

而该pipeline中默认一个tail,head,而后根据业务逻辑,会添加用户指定的handler,而添加时会将handler包装成context. 而后会加入到head为 首部,tail会尾部的链表中。

//封装成Context中
    public ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
        synchronized(this) {
            this.checkDuplicateName(name);
            DefaultChannelHandlerContext newCtx = new DefaultChannelHandlerContext(this, group, name, handler);
            this.addLast0(name, newCtx);
            return this;
        }
    }
//加入到双向链表中
    private void addLast0(String name, AbstractChannelHandlerContext newCtx) {
        checkMultiplicity(newCtx);
        AbstractChannelHandlerContext prev = this.tail.prev;
        newCtx.prev = prev;
        newCtx.next = this.tail;
        prev.next = newCtx;
        this.tail.prev = newCtx;
        this.name2ctx.put(name, newCtx);
        this.callHandlerAdded(newCtx);
    }

也就是将所有的handler(业务的处理逻辑)  封装到了 AbstractChannelHandlerContext  ,每个context又有 prev和 next的 引用。形成了一条双向链表,双向的目的在于 netty中对于消息的 接收(in)与发送(out)。主要的成员变量如下

volatile AbstractChannelHandlerContext next;
volatile AbstractChannelHandlerContext prev;
private final boolean inbound;
private final boolean outbound;
private final AbstractChannel channel;
private final DefaultChannelPipeline pipeline;
private final String name;
ChannelHandler handler(); //父类成员

2)业务的执行

而业务的触发来自channel对事件的处理,如bind,register,read等都会通过pipeline中的方法,将业务引导到链中。如下是chanel注册后的关键逻辑

private void register0(ChannelPromise promise) {
    try {
        if(!promise.setUncancellable() || !this.ensureOpen(promise)) {
            return;
        }
        boolean t = this.neverRegistered;
        AbstractChannel.this.doRegister();
        this.neverRegistered = false;
        AbstractChannel.this.registered = true;
        this.safeSetSuccess(promise);
        AbstractChannel.this.pipeline.fireChannelRegistered();
        if(t && AbstractChannel.this.isActive()) {
            AbstractChannel.this.pipeline.fireChannelActive();
        }
    } catch (Throwable var3) {
        this.closeForcibly();
        AbstractChannel.this.closeFuture.setClosed();
        this.safeSetFailure(promise, var3);
    }

}

而调用 pipeline的  fireChannl**  的方法时,而后在pipeline中

public ChannelPipeline fireChannelActive() {
    this.head.fireChannelActive();
    if(this.channel.config().isAutoRead()) {
        this.channel.read();
    }
 return this;
}

依次逻辑将请求传递到context中。

public ChannelHandlerContext fireChannelActive() {
    final AbstractChannelHandlerContext next = this.findContextInbound();//在链表中,找到下一个context,也就是当前context的next
    EventExecutor executor = next.executor();
    if(executor.inEventLoop()) {
        next.invokeChannelActive();
    } else {
        executor.execute(new OneTimeTask() {
            public void run() {
                next.invokeChannelActive();
            }
        });
    }

    return this;
}
private void invokeChannelActive() {
    try {
        ((ChannelInboundHandler)this.handler()).channelActive(this);// 执行handler的 业务逻辑。
    } catch (Throwable var2) {
        this.notifyHandlerException(var2);
    }

}

而后每个handler根据定义的逻辑,执行,每handler根据定义,一般会继承 adapter,adapter会调用下一,然后tail结束。 一般要重写下面的方法。因为在执行handler的 channle**的 方法里,参数是当前的context(上面介绍 其next和prev的引用),如此一来就会形成一条处理链。

public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
    ctx.fireChannelRegistered();
}

 

2、Tomcat Filter

Tomcat大家都非常熟悉,如果要定义filter通常是在web.xml中定义。然后当我们定义了多个filter时,具体是如何实现的呢?

Tomcat中 类似 于Netty的实现,也有一个chain,在Tomcat中是 

ApplicationFilterChain  ,这个chain 的初始化是在 ApplicationFilterConfig对象数组,而这个 config封装了 Filter,也就是业务逻辑。

同样filter中的doFilter方法中,要将chain做为参数传递进行,其要作为 链执行下去的 必要条件。

 public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        
        chain.doFilter(request, response);
    }

 

3、motan中的 Provider链

motan是新浪微博的rpc框架,其中核心业务是封装成provider对象。

而provider执行的前后 ,增加了一个类似 于责任链的逻辑,完成了一些日志、访问、计数等功能的filter。

首先定义好配置文件,根据其得到filters,首先这里先介绍下filter的filter 方法,其参数有一个为 Caller,而provider实现了该caller。如此意图大家就明白了。如下是日志filter的逻辑,根据需求会在其前后加一些业务逻辑,如访问控制 、日志等。 

    @Override
    public Response filter(Caller<?> caller, Request request) {
        boolean needLog = caller.getUrl().getBooleanParameter(URLParamType.accessLog.getName(), URLParamType.accessLog.getBooleanValue());
        if (needLog) {
            long t1 = System.currentTimeMillis();
            boolean success = false;
            try {
                Response response = caller.call(request);
                success = true;
                return response;
            } finally {
                long consumeTime = System.currentTimeMillis() - t1;
                logAccess(caller, request, consumeTime, success);
            }
        } else {
            return caller.call(request);
        }
    }

 

如下的逻辑就是核心的  provier  链中,每个内部类Provider 是为了封装filter,而privider的方法中调用filter的方法,将下一个provider作为参数传递。从而完成一个处理链。

 private <T> Provider<T> decorateWithFilter(Provider<T> provider, URL url) {
        List<Filter> filters = getFilters(url, MotanConstants.NODE_TYPE_SERVICE);//从配置中得到Filter
        if (filters == null || filters.size() == 0) {
            return provider;
        }
        Provider<T> lastProvider = provider;
        for (Filter filter : filters) {
            final Filter f = filter;
            final Provider<T> lp = lastProvider;
            lastProvider = new Provider<T>() {
                @Override
                public Response call(Request request) {
                    return f.filter(lp, request);
                }

                。。。。。。

       }
}

 

而上面的代码结构中,用到了匿名内部类。在类中所引用的外部的局部变量中,必须用final来修饰。因为闭包,引用外部的参数,但是编译器只支持值copy,而不支持 引用的copy,所以强制 的限制 参数必须用final ,使变量不可变。内外保持变量同步。

https://www.zhihu.com/question/21395848 -- 内部类详解 

总结:

从以上的实际 应用中,都不是纯的责任链。每一个链上的对象并不是直接把 责任推给下方,而是会经过一定的逻辑处理,而后传递给下方处理, 而另一个 通过 责任的直接承担者,并不会直接引用 下一个 承担者,而是封装到一个对象中,该对象来引用一些其它对象,解耦,每个责任只需 业务逻辑,总的业务要一个chain串联起来,而chain中的对象由一个包装了承担者的wrap对象组成。

http://www.cnblogs.com/java-my-life/archive/2012/05/28/2516865.html

转载于:https://my.oschina.net/ovirtKg/blog/824436

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值