Netty基本介绍,参考juejin.cn/post/740884…
1、Netty的责任链模式
1.1 责任链模式实现样例
基于上图,写一个责任链模式的案例如下:
从下面的例子我们可以知道,责任链模式包含下面几个重要的部分:
- HandlerChainContext:hander上下文,也就是责任链中的节点,持有一个handler,并有指向下一个节点的指针
- Handler: 责任处理器
- Pipeline:维护整个责任链,添加删除责任处理器
public class Pipeline {
//handler上下文,维护链表和负责链表的执行
class HandlerChainContext {
HandlerChainContext next;// 持有下一个节点:单链表
AbstractHandler handler;
public HandlerChainContext(AbstractHandler handler) {
this.handler = handler;
}
// 将节点持有下去
void handler(Object arg0) {
this.handler.doHandler(this, arg0);
}
// 继续执行下一个
void runNext(Object arg0) {
if (this.next != null) {
this.next.handler(arg0);
}
}
}
// 持有上下文(可以获得需要的数据,属性)
public HandlerChainContext context = new HandlerChainContext(new AbstractHandler() {
@Override
void doHandler(HandlerChainContext context, Object arg0) {
System.out.println("折扣前"+arg0);
context.runNext(arg0);
}
});
// 添加责任链
public void addLast(AbstractHandler handler) {
HandlerChainContext next = context;
while (next.next != null) {
next = next.next;
}
next.next = new HandlerChainContext(handler);
}
// 开始调用
public void requestProcess(Object arg0) {
context.handler(arg0);
}
//处理器抽象类
static abstract class AbstractHandler {
abstract void doHandler(HandlerChainContext context, Object arg0);
}
//具体的处理器实现类(购物折扣1)
static class Handler1 extends AbstractHandler {
@Override
void doHandler(HandlerChainContext handlerChainContext, Object arg0) {
System.out.println("--首次购买打9折!");
arg0 = new DecimalFormat("0.00").format(Double.valueOf(arg0.toString())*0.9);
System.out.println("折扣后金额:"+arg0);
// 继续执行下一个
handlerChainContext.runNext(arg0);
}
}
//具体的处理器实现类(购物折扣2)
static class Handler2 extends AbstractHandler {
@Override
void doHandler(HandlerChainContext handlerChainContext, Object arg0) {
System.out.println("--满200减20!");
if(Double.valueOf(arg0.toString()) >= 200){
arg0 = Double.valueOf(arg0.toString())-20;
// 继续执行下一个
System.out.println("折扣后金额:"+arg0);
handlerChainContext.runNext(arg0);
}else{
System.out.println("不满足条件,折扣结束:"+arg0);
}
}
}
//具体的处理器实现类(购物折扣3)
static class Handler3 extends AbstractHandler {
@Override
void doHandler(HandlerChainContext handlerChainContext, Object arg0) {
System.out.println("--第二件减10元!");
arg0 = Double.valueOf(arg0.toString())-10;
System.out.println("折扣后金额:"+arg0);
// 继续执行下一个
handlerChainContext.runNext(arg0);
}
}
public static void main(String[] args) {
Pipeline p = new Pipeline();
p.addLast(new Handler1());
p.addLast(new Handler2());
p.addLast(new Handler3());
p.requestProcess("150");
}
}
1.2 Netty的责任处理接口
如下图:责任处理接口分为
1.2.1 ChannelInboundHandler
入站处理器方法(注册、渠道读、渠道激活等等)
1.2.2 ChannelOutboundHandler
出站处理器方法(绑定、连接、读、写、刷新等等)
1.3 责任添加删除接口ChannelPipeline
该接口的唯一实现类DefaultChannelPipeline,该类有HeadContext 和TailContext属性,分别执行责任链的头和尾节点。
1.4 上下文ChannelHandlerContext
该接口有一个抽象类实现AbstractChannelHandlerContext,这个类有prev和next属性,指向责任链的前一个节点和后一个节点。整个责任链是双链表结构。
该接口的handler() 方法返回Context持有的责任处理器handler。
1.5 责任终止机制
- 在pipeline中任意一个节点,只要我们不手动的往下传播,这个事件就会终止传播在当前节点
- 对于入站数据,默认会传递到尾结点,进行回收,如果我们不进行下一步传播,事件就会终止在当前节点,别忘记收回msg
- 对于出站数据,用Header节点的使用Unsafe对象,把数据写回客户端也意味着终止
2、Netty中责任链如何运作?
2.1 我们看一个Netty源码的bind方法样例
我们看一下ServerBootstrap.doBind()方法,所有的bind最终转到这里。继续进入doBind0,如图:
进入下图的channel.bind
2.2 AbstractChannel#bind,调用pipeline,这是责任链模式
2.3 继续进入,我们来到AbstractChannelHandlerContext#bind
看下面红圈的代码,findContextOutbound这行代码用来计算下一步执行责任链上哪一个节点,通过这种方式把责任链执行连起来,后续继续执行就可以,handler的方法都是这样结构的
2.4 掩码MASK_BIND(责任链节点集合,不同责任链执行不同节点)
这两个常量来自下面这个类,我们看到还有很多其他常量,这里表示不同的事件,每个事件占一位,一共16位。
MASK_ONLY_OUTBOUND是出站事件组合出来的,表示出站需要执行的责任节点。不同的掩码表示不同业务的责任链节点集合。
2.5 寻找责任链下一个节点AbstractChannelHandlerContext#findContextInbound
下图是寻找责任链节点的方法,先获取当前节点的下一个节点,然后判断下一个节点是否要执行,不需要的话继续下一个,直到找到需要执行的节点。
这里从一个节点走向下一个节点,直到走完真个责任链。
我们继续看while循环的判断条款skipContext,Context使用传入的mask,也就是MASK_BIND和MASK_ONLY_OUTBOUND做与运算,如果是0的话,说明MASK_ONLY_OUTBOUND不包含绑定操作,该节点不执行,跳过
2.6 执行handler
找到要执行的责任节点后,根据handler类型执行不同的handler的bind方法完成绑定
3、总结:
Netty通过责任链的设计模式是的对事件的处理,符合开闭原则,对新增处理事件开放,对修改责任链逻辑封闭。
将责任处理器分为入站出站的结构很清晰,使用MASK对Handler分类处理,实现了一个轻量级的分类管理,也加快了处理速度。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。