适用场景:
对于一个请求来说, 如果有个对象都有机会处理它, 而且不明确到底是哪个对象会处理请求时, 我们可以考虑使用责任链模式实现它, 让请求从链的头部往后移动, 直到链上的一个节点成功处理了它为止
优点:
发送者不需要知道自己发送的这个请求到底会被哪个对象处理掉, 实现了发送者和接受者的解耦
简化了发送者对象的设计
可以动态的添加节点和删除节点
缺点:
所有的请求都从链的头部开始遍历, 对性能有损耗
极差的情况, 不保证请求一定会被处理
自定义一个责任链
在 java 中不再存在指针了, 如果我们想创建一个链表, 只能是在本类中添加本类属性, 因为我们想创建一个链表, 所以这是必须的工作
需要提供 set 方法, 让当前的节点可以设置自己的下一个节点
处理请求的逻辑, 设计成抽象方法, 让不同的节点根据自己的需求去实现
- public abstract class Approver {
- Approver approver;
- String name;
- // todo 抽象父类中可以存在构造函数, 但是当我们创建子类时, 必须要有一个参数的构造函数,
- // todo 让子类一个参数的构造函数, 来给这个函数初始化
- public Approver (String name){
- this.name=name;
- }
- public abstract void ProcessRequest(PurchaseRequest request);
- // 如果当前的处理器处理不了, 就会往下传播
- public void setApprover( Approver approver){
- this.approver=approver;
- }
- }
PurchaseRequest, 需要被处理的请求, 根据自己的需要各不相同
接着就是链表上的不同功能的节点都要实现上面的抽象类 Approver, 重写它的抽象方法, 添加上他们特定的功能
测试:
- // 创建出各个节点
- Approver1 approver1 = new Approver1();
- Approver2 approver2 = new Approver2();
- Approver3 approver3 = new Approver3();
- // 设置他们关系
- approver1.setApprover(approver2);
- approver2.setApprover(approver3);
- // 发起请求
- Client client = new Client();
- PurchaseRequest purchaseRequest = client.sendRequest();
- // 处理请求
- tom.ProcessRequest(purchaseRequest);
把请求传递给责任链的第一个节点, 她会自动往后传播下去, 直到有一个节点成功处理了它
Netty 的责任链设计
netty 的 pipeline 设计, 就采用了责任链设计模式, 底层采用双向链表的数据结构, 将链上的各个处理器串联起来
客户端每一个请求的到来, netty 都认为, pipeline 中的所有的处理器都有机会处理它, 因此, 对于入栈的请求, 全部从头节点开始往后传播, 一直传播到尾节点 (来到尾节点的 msg 会被释放掉)
netty 的责任链模式中的组件
责任处理器接口
pipeline 中的处理器都它的具体实现
添加删除责任处理器的接口
上下文
通过这个上下文, 可以获得需要的数据, 属性
责任终止机制
pipeline 中的每一个节点, 都可以终止事件的传播
netty 的责任处理器接口
责任处理器接口, pipeline 中的所有的 handler 的顶级抽象接口, 它规定了所有的 handler 统一要有添加, 移除, 异常捕获的行为
- public interface ChannelHandler {
- // todo 当 handler 被添加到真实的上下文中, 并且准备处理事件时被调用
- // todo handler 被添加进去的回调
- void handlerAdded(ChannelHandlerContext ctx) throws Exception;
- // todo 是 handler 被移出的后的 回调
- void handlerRemoved(ChannelHandlerContext ctx) throws Exception;
- @Deprecated
- void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;
- @Inherited
- @Documented
- @Target(ElementType.TYPE)
- @Retention(RetentionPolicy.RUNTIME)
- @interface Sharable {
- // no value
- }
- }
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, 以及它的线程执行器
- // todo AttributeMap -- 让 ChannelHandlerContext 可以存储自定义的属性
- // todo ChannelInboundInvoker -- 让 ChannelHandlerContext 可以进行 InBound 事件的传播, 读事件, read 或者是 注册事件 active 事件
- // todo ChannelOutboundInvoker -- 让 ChannelHandlerContext 可以传播写事件
- public interface ChannelHandlerContext extends AttributeMap, ChannelInboundInvoker, ChannelOutboundInvoker {
- // todo 获取 ChannelHandlerContext 所对应的这个 Channel 对象
- Channel channel();
- // todo 获取事件执行器
- EventExecutor executor();
- ...
责任终止机制
责任终止机制
在 pipeline 中的任意一个节点, 只要我们不手动的往下传播下去, 这个事件就会终止传播在当前节点
对于入站数据, 默认会传递到尾节点, 进行回收, 如果我们不进行下一步传播, 事件就会终止在当前节点, 别忘记回收 msg
对于出站数据, 用 header 节点的使用 unsafe 对象, 把数据写会客户端也意味着事件的终止
事件的传播
底层事件的传播使用的就是针对链表的操作
- private AbstractChannelHandlerContext findContextInbound() {
- AbstractChannelHandlerContext ctx = this;
- do {
- ctx = ctx.next;
- } while (!ctx.inbound);
- return ctx;
- }
来源: https://www.cnblogs.com/ZhuChangwu/p/11241304.html