责任链模式的使用-Netty ChannelPipeline和Mina IoFilterChain分析

本文来自网易云社区

作者:乔安然

1. Chain of Responsiblity

定义:

使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理他为止。

结构实图:

2. Netty ChannelPipeline 分析

Netty的ChannelPipeline和ChannelHandler机制类似于Servlet和Filter过滤器,这类过滤器其实就是责任链模式的一种变形,方便事件的拦截和用户业务逻辑的定制且相互不必耦合在一起。

Netty将Channel的数据管道抽象为ChannelPipeline,消息在ChannelPipline中流动和传递。ChannelPipeline持有IO事件拦截器ChannelHandler的链表,由ChannelHandler对IO事件进行拦截和处理,可以方便的新增和删除ChannelHandler来实现不同的业务逻辑定制,不必对已有的ChannelHandler进行修改,这个开放闭合原则的很好体现。

下面我们对ChannelPipeline和ChannelHandler,以及相关的ChannelHandlerContext进行详细介绍和源码分析。

先看下ChannlePipeline的事件事件处理流程,如下图

  1. 底层Socket读取bytebuf触发ChannelRead事件(Inbound 事件),由NioEventLoop调用ChannelPipeline的fireChannelRead方法
  2. 消息被ChannelPipeline中的ChannelHandlerContext传递,依次被各个ChannelHandler处理
  3. 当有写出的需求(Outbound 事件),调用ChannelHandlerContext write方法,消息再通过ChannelHandlerContext反向传递通过各个ChannelHandler处理。当然各个ChannelHadler可以通过定制只对自己感兴趣的消息进行处理,其余跳过。

下图是ChannelPipeline相关的类UML图

DefaultChannelPipeline:I/O事件承载的数据管道,由ChannelHandlerContext节点组成双链表结构

ChannelHandler: I/O事件的处理层,分别为Inbound和outbound两种事件类型派生ChannelInboundHandler和ChannelOutboundHandler接口,如上图中的MessageToMessageDecoder和MessageToMessageEncoder类分别对消息的解码和编码处理。用户在实际使用中根据需求处理Inbound还是outbound事件。

DefaultChannelHandlerContext:组成pipeline的节点,执行handler的上下文环境,支持异步模式,如下面read事件处理:

 @Override
    public ChannelHandlerContext fireChannelRead(final Object msg) {        // 找到下一个inbound的handler
        invokeChannelRead(findContextInbound(), msg);        return this;
    }    static void invokeChannelRead(final AbstractChannelHandlerContext next, Object msg) {        final Object m = next.pipeline.touch(ObjectUtil.checkNotNull(msg, "msg"), next);
        EventExecutor executor = next.executor();        // 判断是否由内部触发
        if (executor.inEventLoop()) {
            next.invokeChannelRead(m);
        } else {            // 外部触发异步处理
            executor.execute(new Runnable() {                @Override
                public void run() {
                    next.invokeChannelRead(m);
                }
            });
        }
    }   // 触发handler中的channelRead方法,对消息进行处理
    private void invokeChannelRead(Object msg) {        if (invokeHandler()) {            try {
                ((ChannelInboundHandler) handler()).channelRead(this, msg);
            } catch (Throwable t) {
                notifyHandlerException(t);
            }
        } else {
            fireChannelRead(msg);
        }
    }

3.Mina IoFilterChain分析

责任链模式在mina中也发挥着重要的作用,其中Filter机制就是基于责任链实现的,来看下mina框架组成

从上图看到消息的接受从IoService层先经过Filter层过滤处理后最后交给IoHander,消息的发送则是反过来从IoHander层经过Filter层再到IoService层。由此可以看到netty和mina对消息处理都是相似的。

从图中看到接收消息和发送消息经过Filter层是相反处理的,那么每个Filter就必须知道前一个和后一个Filter,那么mina中的Filter层和netty的pipeline相同都是使用双向链表实现的,那么让我们来看看Filter层具体是如何实现

mina的filterchain包结构:

Filter层的每个filter都是对上图IoFilter接口的实现,我们将具体讲解IoFilter,IoFilterChain,DefaultIoFilterChain这几个类

IoFilterChainBuilder接口和DefaultIoFilterChainBuilder实现不再细讲,从字面意思就是IoFilterChain的建造者

IoFilterEvent是代表filter事件,IoFilterLifeCycleException是指加入链表异常

下面的图是我们要重点讲解的几个类的关系

IoFilter接口:NextFilter接口是其内部接口

IoFilterAdapter类:对IoFilter接口的实现,是所有Filter的基类

IoFilterChain接口:Entry接口是其内部接口

DefaultIoFilterChain类:是对IoFilterChain接口的实现,有EntryImpl,HeadFilter,TailFilter三个内部类,其中EntryImpl类中又有NextFilter接口的内部实现

还需要说明下:IoFilter还有相关接口就写了两个方法,一个接受消息触发的方法还有一个是发送消息触发的方法,剩下的都是这两类消息处理方法就不表示了,这和netty中的inbound、outbound相同

HeadFilter类只对发送消息处理方法重载,TailFilter类只对接受消息处理方法重载

从上图看到EntryImp类是重点,我们就来看看EntryImpl类的实现

private class EntryImpl implements Entry {        private EntryImpl prevEntry ;        private EntryImpl nextEntry ;        private final String name;        private IoFilter filter ;        private final NextFilter nextFilter;        private EntryImpl(EntryImpl prevEntry, EntryImpl nextEntry, String name, IoFilter filter) {            if (filter == null) {                throw new IllegalArgumentException("filter");
            }            if (name == null) {                throw new IllegalArgumentException("name");
            }            this.prevEntry = prevEntry;            this.nextEntry = nextEntry;            this.name = name;            // 业务的fliter处理层
            this.filter = filter;            // 调度filter对读入和写出消息处理
            this.nextFilter = new NextFilter() {               // 读入消息调用nextEntry处理
                public void sessionOpened(IoSession session) {
                    Entry nextEntry = EntryImpl. this.nextEntry ;
                    callNextSessionOpened(nextEntry, session);
                }                // 写出消息调用preEntry反向处理
                public void filterWrite(IoSession session, WriteRequest writeRequest) {
                    Entry nextEntry = EntryImpl. this.prevEntry ;
                    callPreviousFilterWrite(nextEntry, session, writeRequest);
                }

            };
        }

从EntryImpl类的构造方法看到,EntryImpl中保持对上一个节点和下一个节点引用,双向链表结构,name即过滤层名称,filter即过滤层的具体实现,而nextFilter是在构造方法中的内部实现。

下面我们来看看sessionOpen处理的完整过程,sessionOpen事件属于读入对应netty中的inbound事件类型。首先是IoFilterChain收到这个消息触发fireSessionOpened方法

 public void fireSessionOpened() {
        Entry head = this.head ;
        callNextSessionOpened(head, session);
    }    private void callNextSessionOpened(Entry entry, IoSession session) {        try {
            IoFilter filter = entry.getFilter();
            NextFilter nextFilter = entry.getNextFilter();
            filter.sessionOpened(nextFilter, session);
        } catch (Throwable e) {
            fireExceptionCaught(e);
        }
    }

fireSessionOpened方法获取当前的头节点,然后调用callNextSessionOpened方法,而callNextSessionOpened方法是从entry中获取filter和nextfitler,触发filter的sessionOpened方法,同时将nextfilter作为参数传进去,而filter层如果对这个消息感兴趣可以处理完成后调用nextfilter的sessionOpened方法,不感兴趣的话,可能消息到此就结束了。

由此可看出mina中的Fliter和netty的ChannelHandler功能相同,而NextFilter其实是起到中转和调度的作用,收到Reveceive消息转交给后一节点,收到Send消息转交给前一个消息。这和netty中ChannelHandlerContext功能相似。

mina和netty不相同的一点对异步多线程的使用,netty中ChannelHandlerContext中加入对异步支持,而mina中代之以一个更通用的系统,基于一个过滤器:ExecutorFilter。当Fliter层将消息事件传递到ExecutorFilter中,它包含一个Executor来将消息事件传递给线程池运行处理。

本文来自网易云社区,经作者马宝授权发布

网易云免费体验馆,0成本体验20+款云产品!

更多网易研发、产品、运营经验分享请访问网易云社区

相关文章:
【推荐】 什么是高防服务器?

原文地址:https://www.cnblogs.com/zyfd/p/9667129.html

时间: 2024-10-06 00:33:36

责任链模式的使用-Netty ChannelPipeline和Mina IoFilterChain分析的相关文章

java 设计模式 -- 责任链模式

设计模式 – 责任链模式 介绍: 责任链模式是一种动态行为模式,有多个对象,每一个对象分别拥有其下家的引用.连起来形成一条链.待处理对象则传到此链上,在此链进行传递,且待处理对象并不知道此会被链上的哪个对象处理,这使得我们能够动态的添加链上的对象而且分配责任. 纯责任链和非纯责任链 责任链分为两种.纯责任链和非纯责任链. 纯责任链是待处理对象request在处理对象handler链上传递,每一个处理对象handler处理request的一部分,到终于处理完毕.非纯责任链则是待处理对象reques

java23种设计模式之十:责任链模式

最近在学习netty中发现其中用到了责任链模式,然后结合自己在写代码中遇到了大量写if...else的情况,决定学习一下责任链模式. 一.什么样的场景下会选择用责任链模式 我们在进行业务逻辑判断时,需要根据传入参数类型的不同做出不同的处理,如果在传入的参数类型相对较少的情况时,可以用if...else来做判断,这样的确是没有什么问题的,但是如果后期由于业务系统的扩展,导致参数类型会随之延伸出很多种不同的处理,这时就需要用责任链模式来抒代码重构,这样会让代码封装的更好.更简洁,阅读性更强,后期如果

设计模式之责任链模式--- Pattern chain-of-responsibility

模式的定义 责任链模式定义如下: 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. 使多个对象都有机会处理请求,从而避免请求的发送

大量逻辑判断优化的思路——责任链模式复习总结及其和状态模式对比

俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习!涉及的总结知识点如下: 责任链模式概念和例子 使用的条件 和状态模式的比较分析 责任链的优缺点 纯的责任链和不纯的责任链 javax.servlet.Filter#doFilter()方法源码分析 基于AOP思想,模拟一个拦截器 前面说了一个状态模式,总结过程中发现和这个责任链的使用场景很类似,都是为了解耦大量复杂业务逻辑判断的,那么他们有什么不同呢?回忆状态模式——状态模式允许通过改变对象的内部状态而改变对象自身的行为,这个对象

JAVA设计模式(13):行为型-责任链模式(Responsibility)

定义 将能够处理同一类请求的对象连成一条链,所提交的请求沿着链传递,链上的对象逐个判断是否有能力处理该请求, 如果能则处理,如果不能则传递给链上的一个对象. 场景: 打牌时,轮流出牌 接力赛跑 大学中,奖学金审批 公司中,公文审批 开发中常见的场景: Java中,异常机制就是一种责任链模式.一个try可以对应多个catch,当第一个catch不匹配类型,则自动跳到第二个catch. Javascript语言中,事件的冒泡和捕获机制.Java语言中,事件的处理采用观察者模式. Servlet开发中

设计模式_责任链模式

定义 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.(使多个对象都有机会处理请求.从而避免了请求的发送者和接受者之间的耦合关系.

5 行为型模式之- 责任链模式

责任链模式介绍: 责任链模式是行为模式之一,什么是"链"?我们将多个节点首尾相连,就形成了链,对于链式结构,每个节点都可以拆开再重新连接,因此链式结构也具有很好的灵活性.将这样一种结构应用于编程领域,将每一个节点看作是一个对象,每一个对象拥有不同的处理逻辑,将一个请求从一个链的首端发出,沿着链的路径依次传递给每一个节点对象,直至有对象处理这个请求为止,我们将这样的一种模式称为责任链模式. 责任链模式的定义: 使多个对象都有机会处理请求,从而避免了请求的发送者和接收者之间的耦合关系,将这

责任链模式

案例分析 责任链模式可以通过形象的生活例子进行解读,不管是前端攻城狮还是后端攻城狮,责任链的思想都有所体现(框架之中) 击鼓传花 老太和一群姑娘准备玩击鼓传花的游戏,于是找来了一个击鼓的人,游戏规则就是:随着鼓点声音,从她们之间传递一束花,鼓声落,传花停.花最后传递到那个姑娘的手中,那么就由她来给大家即兴赋诗一首. 那么击鼓的人并不需要知道玩游戏的这些人是谁,只需要击鼓即可,相当于客户端发送一个请求,请求在这些姑娘之间传递,总会有一个姑娘最后接到花,给大家赋诗.(一层层的传递请求,总会有一层来对

[设计模式] javascript 之 责任链模式

责任链模式:定义 责任链接模式又称职责链模式,是一种对象的行为模式:它是一种链式结构,每个节点都有可能两种操作,要么处理该请求停止该请求操作,要么把请求转发到下一个节点,让下一个节点来处理请求:该模式定义了一些可能的处理请求的节点对象,请求的起点跟顺序都可能不一样,处理的节点根据请求的不一样而不同:请求者不必知道数据处理完成是由谁来操作的,内部是一个黑箱的操作过程,这是它的一个核心内容: 责任链模式:角色 抽象处理者角色:定义处理方法,以配置是否具有下个节点(Handler)对象; 具体处理者角