责任链模式
适用场景:对于一个请求来说,如果每个对象都有机会处理它,而且不明确到底是哪个对象会处理请求时,我们可以考虑使用责任链模式实现它,让请求从链的头部往后移动,直到链上的一个节点成功处理了它为止
优点:
- 发送者不需要知道自己发送的这个请求到底会被哪个对象处理掉,实现了发送者和接受者的解耦
- 简化了发送者对象的设计
- 可以动态的添加节点和删除节点
缺点:
- 所有的请求都从链的头部开始遍历,对性能有损耗
- 极差的情况,不保证请求一定会被处理
Netty中的应用
netty的pipeline
设计,就采用了责任链设计模式, 底层采用双向链表的数据结构, 将链上的各个处理器串联起来。客户端每一个请求的到来,netty都认为pipeline
中的所有的处理器都有机会处理它,因此,对于入栈的请求,全部从头节点开始往后传播,一直传播到尾节点
netty责任链模式中的组件:
- 责任处理器接口:
ChannelHandler
、ChannelInboundHandler
、ChannelOutboundHandler
- 创建链,添加删除责任处理器接口:
ChannelPipeline
- 上下文:
ChannelHandlerContext
- 责任终止机制
责任处理器接口
责任处理器接口, pipeline
中的所有的handler
的顶级抽象接口,它规定了所有的handler
统一要有添加、移除、异常捕获的行为。除此之外,netty对责任处理接口,做了更细粒度的划分, 处理器被分成了两种, 一种是入站处理器ChannelInboundHandler
,另一种是出站处理器ChannelOutboundHandler
,这两个接口都继承自ChannelHandler
public interface ChannelHandler {
//当handler被添加到真实的上下文中,并且准备处理事件时被调用,handler被添加进去的回调
void handlerAdded(ChannelHandlerContext ctx) throws Exception;
//是handler被移出的后的回调
void handlerRemoved(ChannelHandlerContext ctx) throws Exception;
@Deprecated
void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;
}
创建链,添加删除责任处理器接口
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
, 以及它的线程执行器
// AttributeMap -- 让ChannelHandlerContext 可以存储自定义的属性
// ChannelInboundInvoker -- 让ChannelHandlerContext 可以进行InBound事件的传播,读事件或者是注册事件
// ChannelOutboundInvoker -- 让ChannelHandlerContext 可以传播写事件
public interface ChannelHandlerContext extends AttributeMap, ChannelInboundInvoker,ChannelOutboundInvoker {
//获取ChannelHandlerContext所对应的这个Channel对象
Channel channel();
//获取事件执行器
EventExecutor executor();
...
}
责任终止机制
- 在pipeline中的任意一个节点,只要我们不手动的往下传播下去,这个事件就会终止传播在当前节点
- 对于入站数据,默认会传递到尾节点,进行回收,如果我们不进行下一步传播,事件就会终止在当前节点
- 对于出站数据,用header节点的unsafe对象,把数据写会客户端也意味着事件的终止