「蘑菇街技术」每个人都想听的技术解析--Netty( 四 )


「蘑菇街技术」每个人都想听的技术解析--Netty文章插图
3. Reactor主从多线程模型
服务端用于接收客户端连接的不再是单个NIO线程 , 而是分配了一个独立的NIO线程池 。 Acceptor接收到客户端TCP连接请求并处理完成后(可能包含接入认证等) , 将新创建的SocketChannel注册到I/O线程池(Sub Reactor子线程池)的某个I/O线程上 , 由它负责SocketChannel的读写和编解码工作 。 Acceptor线程池仅仅用于客户端的登录、握手和安全认证 , 一旦链路建立成功 , 就将链路注册到后端Sub Reactor子线程池的I/O线程上 , 再由I/O线程负责后续的I/O操作 。
「蘑菇街技术」每个人都想听的技术解析--Netty文章插图
Pipeline模式在Netty中的应用
实际在Netty使用的到的设计模式有很多 , 包括Bootstrap创建时用到的build模式, ChannelPipeline中使用到的责任链模式 , Channel实例化时使用到的工厂模式等等 , 这里我们会主要介绍一下Pipeline模式在Netty中的应用 。
什么是责任链模式呢?
责任链模式由一个或多个不同的责任处理器组成 , 它会将多个处理器串成链 , 然后让请求在链上传递 , 直到被某个处理器终止 。 那它有什么好处呢?1. 最直观的就是将请求者和接收者解耦 2. 可以让业务以插件式的方式封装到不同的处理器中 , 每个处理器各司其职 。
责任链中的核心组件
一个较为完善的责任链实现应该由责任链处理器、责任链、责任链上下文组成 。
+ 责任处理器: 首先整条链路应该是由一个个责任处理器Handler来组成 , 对此我们可以设计一个处理器接口Handler,其中定义invoke执行相应的handler的业务逻辑 , 而其方法的入参也就是上下文BasicPipelineContext就像一根绳子一样把一个个Handler串起来 , 不仅可以给我们提供数据信息 , 还可以提供整个pipeline的执行状态信息 。
+ 责任链: 一般情况下 , 责任链会包含创建链 , 删除或添加责任处理器等方法;
+ 责任链上下文:让责任处理接口感知到你的上下文 , 通过上下文拿到对应的参数和状态
Netty中的责任链模式
先来介绍一下Netty中的责任链相关组件
+ ChannelHandler: 责任处理器 , 从它的方法里我们也可以看到它可以处理多种事件 。 如添加或删除Handler
public interface ChannelHandler {void handlerAdded(ChannelHandlerContext ctx) throws Exception;void handlerRemoved(ChannelHandlerContext ctx) throws Exception;...}+ ChannelPipeline:也就是责任链 , 包含链的创建、添加、删除责任处理器方法
public interface ChannelPipeline extends ChannelInboundInvoker, ChannelOutboundInvoker, Iterable {ChannelPipeline addFirst(String name, ChannelHandler handler);ChannelPipeline addLast(String name, ChannelHandler handler);....}+ ChannelHandlerContext: 也就是单条责任链的上下文 , 包含与之关联的Channel、执行线程.
public interface ChannelHandlerContext extends AttributeMap, ChannelInboundInvoker, ChannelOutboundInvoker {Channel channel();EventExecutor executor();String name();...}Pipeline在Netty中的执行流程
Bootstrap b = new Bootstrap();b.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true).handler(new ChannelInitializer() {@Overridepublic void initChannel(SocketChannel ch) throws Exception {ChannelPipeline p = ch.pipeline();p.addLast("1", new InboundHandlerA());p.addLast("2", new InboundHandlerB());p.addLast("3", new OutboundHandlerA());p.addLast("4", new OutboundHandlerB());p.addLast("5", new InboundHandlerC());}});ChannelFuture f = b.connect(HOST, PORT).sync();f.channel().closeFuture().sync();如上代码只是模拟客户端 , 其中我们在添加业务处理Handler了的时候便使用到了责任链模式 , 所以我们核心主要关注BootStrap中的handler方法 , 在这个方法中我们将5个不同的Handler依次添加到pipeline中 , 那么在Netty中要怎么创建ChannelPipeline呢?其实Netty在实例化channel的时候 , 便会自动在AbstractChannel构造器中创建相应的ChannelPipeline , 在AbstractChannel的构造器中最终会将其初始化为DefaultChannelPipeline , 具体初始化逻辑如下代码 , 从这段代码里我们便可以的知道Netty中的Pipeline的底层本质便是一个双向链表 , 并且它的头节点和尾节点在初始化Channel的时候 , 便由DefaultChannelPipeline构造器中创建完成 。
protected DefaultChannelPipeline(Channel channel) {this.channel = ObjectUtil.checkNotNull(channel, "channel");succeededFuture = new SucceededChannelFuture(channel, null);voidPromise =new VoidChannelPromise(channel, true);tail = new TailContext(this);head = new HeadContext(this);head.next = tail;tail.prev = head;}