责任链模式

责任链模式的定义:使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系, 将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理他为止。责任链模式的重点在“链上”,由一条链去处理相似的请求,在链中决定谁来处理这个请求,并返回相应的结果。

Netty的责任链设计

 netty的pipeline设计,就采用了责任链设计模式, 底层采用双向链表的数据结构, 将链上的各个处理器串联起来

 客户端每一个请求的到来,netty都认为,pipeline中的所有的处理器都有机会处理它,因此,对于入栈的请求,全部从头节点开始往后传播,一直传播到尾节点(来到尾节点的msg会被释放掉)

netty的责任链模式中的组件

a.责任处理器接口:pipeline中的处理器都有它的具体实现
b.添加删除责任处理器的接口

c.上下文:通过这个上下文,可以获得需要的数据,属性
d.责任终止机制:pipeline中的每一个节点,都可以终止事件的传播

netty的责任处理器接口

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package io.netty.channel;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

public interface ChannelHandler {

    //  当handler被添加到真实的上下文中,并且准备处理事件时被调用
    //  handler 被添加进去的回调
    void handlerAdded(ChannelHandlerContext var1) throws Exception;

    //  是 handler 被移出的后的 回调
    void handlerRemoved(ChannelHandlerContext var1) throws Exception;

    /** @deprecated */
    @Deprecated
    void exceptionCaught(ChannelHandlerContext var1, Throwable var2) throws Exception;

    @Inherited
    @Documented
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Sharable {
    }
}

netty对责任处理接口,做了更细粒度的划分, 处理器被分成了两种, 一种是站处理器ChannelInboundHandler,另一种是出站处理器ChannelOutboundHandler,这两个接口都继承自ChannelHandler

添加删除责任处理器的接口
netty中所有的处理器最终都在添加在pipeline上,所以,添加删除责任处理器的接口的行为在 netty channelPipeline中的进行了规定

public interface ChannelPipeline
        extends ChannelInboundInvoker, ChannelOutboundInvoker, Iterable<Entry<String, ChannelHandler>> {

    ChannelPipeline addFirst(String name, ChannelHandler handler);

    ChannelPipeline addFirst(EventExecutorGroup group, String name, ChannelHandler handler);

    ChannelPipeline addLast(String name, ChannelHandler handler);

    ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler);

    ChannelPipeline addBefore(String baseName, String name, ChannelHandler handler);

 ...

上下文

pipeline中的handler被封装进了上下文中,如下, 通过上下文,可以轻松拿到当前节点所属的channel, 以及它的线程执行器

package io.netty.channel;

import io.netty.buffer.ByteBufAllocator;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import io.netty.util.AttributeMap;
import io.netty.util.concurrent.EventExecutor;
// todo AttributeMap:让ChannelHandlerContext 可以存储自定义的属性
// ChannelInboundInvoker:让ChannelHandlerContext 可以进行InBound事件的传播,
//读事件,read 或者是  注册事件 active事件
// ChannelOutboundInvoker -- 让ChannelHandlerContext 可以传播写事件
public interface ChannelHandlerContext extends AttributeMap, ChannelInboundInvoker, ChannelOutboundInvoker {
    Channel channel();

    EventExecutor executor();

    .....
}

责任终止机制

在pipeline中的任意一个节点,只要我们不手动的往下传播下去,这个事件就会终止传播在当前节点
对于入站数据,默认会传递到尾节点,进行回收,如果我们不进行下一步传播,事件就会终止在当前节点,别忘记回收msg
对于出站数据,用header节点的使用unsafe对象,把数据写会客户端也意味着事件的终止

Netty的责任链模式各个类的职责如下: 
Channel:封装了jdk原生的channel,提供统一的API,作为其它各个功能组件的容器。

ChannelPipeline:责任链模式的核心组件,ChannelHandler的容器,按顺序组织各个ChannelHandler,并在它们之间转发事件。

ChannelHandlerContext:封装一个具体的ChannelHandler,并为ChannelHandler的执行提供一个线程环境(ChannelHandlerInvoker)可以理解为ChannelPipeline链路上的一个节点,节点里面包含有指向前后节点的指针,事件在各个ChannelHandler之间传递,靠的就是ChannelHandlerContext。

ChannelHandlerInvoker:顾名思义,是ChannelHandler的一个Invoker,它存在的意义是为ChannelHandler提供一个运行的线程环境,默认的实现DefaultChannelHandlerInvoker有一个EventExecutor类型的成员,就是Netty的EventLoop线程,所以默认ChannelHandler的处理逻辑在EventLoop线程内。当然也可以提供不同的实现,替换默认的线程模型。

ChannelHandler: 真正对IO事件作出响应和处理的地方,也是Netty暴露给业务代码的一个扩展点。一般来说,主要业务逻辑就是以自定义ChannelHandler的方式来实现的。

总结:

关于Netty责任链模式,重点应了解ChannelPipeline,及DefaultChannelPipeline这个默认的实现类,这其实就是一个链表管理类,管理者每一个ChannelHandlerContext类型的节点,从它的addFirst、addLast、remove等成员方法就可以看出来。

ChannelHandler是一个顶级接口,有两个子接口ChannelInboundHandler和ChannelOutboundHandler分别处理read和write相关的IO事件,为了便于业务方实现,两个子接口分别有一个简单的Adapter实现类,所有方法的默认实现都是代理给ChannelHandlerContext类(其实是不关心事件,直接转发给pipeline中下一个节点的handler来处理)。业务方实现自己的ChannelHandler时,推荐继承相应的Adapter类,只实现自己关心的事件的处理方法。