Netty中的责任链模式

简介: Netty中的责任链模式

适用场景:

  • 对于一个请求来说,如果有个对象都有机会处理它,而且不明确到底是哪个对象会处理请求时,我们可以考虑使用责任链模式实现它,让请求从链的头部往后移动,直到链上的一个节点成功处理了它为止

优点:

  • 发送者不需要知道自己发送的这个请求到底会被哪个对象处理掉,实现了发送者和接受者的解耦
  • 简化了发送者对象的设计
  • 可以动态的添加节点和删除节点

缺点:

  • 所有的请求都从链的头部开始遍历,对性能有损耗
  • 极差的情况,不保证请求一定会被处理


自定义一个责任链#


在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;
}
相关文章
|
6月前
|
编解码 开发者
Netty Review - 深入理解Netty: ChannelHandler的生命周期与事件处理机制
Netty Review - 深入理解Netty: ChannelHandler的生命周期与事件处理机制
142 0
|
负载均衡 算法 Java
Netty源码分析系列之五:Netty多线程模型
本文主要介绍了Netty的多线程模型,它采用的是Reactor模型。处理连接请求与处理IO操作的线程隔离。基于事件轮询监听,不断获取处于就绪状态的通道。其中Boss线程池的线程负责处理连接请求,接收到accept事件之后,将对应的socket进行封装生成NioSocketChannel对象,并将其提交到workBoss线程池中,处理IO的read以及write事件。
Netty源码分析系列之五:Netty多线程模型
|
编解码
Netty源码剖析之Netty启动流程
了解netty启动流程,有助于学习netty,进行自定义组件扩展
133 0
|
设计模式 缓存 分布式计算
Netty源码剖析之线程模型
1. NIO 的类库和 API 繁杂,使用麻烦:需要熟练掌握 Selector、ServerSocketChannel、SocketChannel、ByteBuffer等。 2. 需要具备其他的额外技能:要熟悉 Java 多线程编程,因为 NIO 编程涉及到 Reactor 模式,必须对多线程和网络编程非常熟悉,才能编写出高质量的 NIO 程序。 3. 开发工作量和难度都非常大:例如客户端面临断连重连、网络闪断、半包读写、失败缓存、网络拥塞和异常流的处理等等。 4. JDK NIO 的 Bug:臭名昭著的 Epoll Bug,它会导致 Selector 空轮询,最终导致 CPU 100%
132 0
|
Java 应用服务中间件 nginx
Netty实战与源码剖析(三)——Netty线程模型
Netty实战与源码剖析(三)——Netty线程模型
225 0
Netty实战与源码剖析(三)——Netty线程模型
|
网络协议 安全 Java
Netty(三)Netty线程模型源码剖析
Netty(三)Netty线程模型源码剖析
100 0
|
负载均衡 算法 应用服务中间件
Netty框架入门(二)之基于Netty实现简单的Rpc调用
Netty框架入门(二)之基于Netty实现简单的Rpc调用
198 0
Netty框架入门(二)之基于Netty实现简单的Rpc调用
|
设计模式 容器
Netty中的装饰者模式
Netty中的装饰者模式
124 0
|
分布式计算 网络协议 Java
Netty实现原理分析
Netty实现原理分析
258 0
Netty实现原理分析
|
数据处理
Netty原理:ChannelHandler
Netty原理:ChannelHandler
Netty原理:ChannelHandler