ChannelPipeline数据管道是ChannelHandler数据处理器的容器,负责ChannelHandler的管理和事件的拦截与调度
个人主页:tuzhenyu’s page
原文地址:Netty源码分析(三)—数据管道ChannelPipeline源码分析
private void connect(String host,int port){
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY,true)
.handler(new ChannelInitializer() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline ch = socketChannel.pipeline();
ch.addLast(new TimeClientHandler());
}
});
ChannelFuture f = b.connect(host,port).sync();
f.channel().closeFuture().sync();
}catch (Exception e){
e.printStackTrace();
}finally {
group.shutdownGracefully();
}
}
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
channel = this.channelFactory.newChannel(); //创建
this.init(channel); //初始化
} catch (Throwable var3) {
if(channel != null) {
channel.unsafe().closeForcibly();
}
return (new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE)).setFailure(var3);
}
ChannelFuture regFuture = this.config().group().register(channel); //注册
if(regFuture.cause() != null) {
if(channel.isRegistered()) {
channel.close();
} else {
channel.unsafe().closeForcibly();
}
}
return regFuture;
}
ChannelPipeline数据管道是与Channel通道绑定的,一个Channel通道对应一个ChannelPipeline,channelpipeline是在Channel初始化时候被创建;
在Channel实例化时会通过newInstance()方法调用构造器创建实例,NioServerSocketChannel和NioSocketChannel都继承了AbstractChannel,在创建实例时候也会调用AbstractChannel构造器;在AbstractChannel构造器中会创建pipeline管道实例
protected AbstractChannel(Channel parent) {
this.parent = parent;
unsafe = newUnsafe();
pipeline = new DefaultChannelPipeline(this);
}
创建DefaultChannelPipeline类型的对象指向channelPipeline属性
pipeline内维护着一个以 AbstractChannelHandlerContext 为节点的双向链表,创建的head和tail节点分别指向链表头尾
TailContext和headContext都继承了AbstractChannelHandlerContext并是实现了ChannelHandler接口,AbstractChannelHandlerContext内部维护着next,pre链表指针和inbound,outbound节点方向等;TaileContext实现了ChannelInboundHandler,headContext实现了ChanneloutboundHandler;
public DefaultChannelPipeline(AbstractChannel channel) {
if (channel == null) {
throw new NullPointerException("channel");
}
this.channel = channel;
tail = new TailContext(this);
head = new HeadContext(this);
head.next = tail;
tail.prev = head;
}
void init(Channel channel) throws Exception {
ChannelPipeline p = channel.pipeline();
p.addLast(new ChannelHandler[]{this.config.handler()});
Map options = this.options0();
synchronized(options) {
setChannelOptions(channel, options, logger);
}
Map attrs = this.attrs0();
synchronized(attrs) {
Iterator var6 = attrs.entrySet().iterator();
while(var6.hasNext()) {
Entry e = (Entry)var6.next();
channel.attr((AttributeKey)e.getKey()).set(e.getValue());
}
}
}
调用pipeline.addLast()方法添加handler到pipeline管道中,该handler为初始化时配置的ChannelInitializer对象;
ChannelInitializer继承了ChannelInboundHandlerAdapter,它提供了一个 initChannel 方法供我们初始化自定义ChannelHandler;在调用addLast()方法时会创建一个DefaultChannelHandlerContext节点用来存放ChannelInitializer,因为ChannelInitializer继承了ChannelInboundHandlerAdapter所以节点的inbound属性为true,outbound属性为false;
public final ChannelHandler handler() {
return this.bootstrap.handler();
}
bootstrap.handler(new ChannelInitializer() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline ch = socketChannel.pipeline();
ch.addLast(new TimeClientHandler());
}
});
public ChannelPipeline fireChannelRegistered() {
head.fireChannelRegistered();
return this;
}
public ChannelHandlerContext fireChannelRegistered() {
final AbstractChannelHandlerContext next = findContextInbound();
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
next.invokeChannelRegistered();
} else {
executor.execute(new OneTimeTask() {
@Override
public void run() {
next.invokeChannelRegistered();
}
});
}
return this;
}
private void invokeChannelRegistered() {
if(this.invokeHandler()) {
try {
((ChannelInboundHandler)this.handler()).channelRegistered(this);
} catch (Throwable var2) {
this.notifyHandlerException(var2);
}
} else {
this.fireChannelRegistered();
}
}
调用ChannelInitializer节点的channelRegistered()方法添加自定义节点删除初始节点
调用initChannel()方法,通过addLast()向链表尾部添加自定义Handler
删除ChannelInitializer节点
public final void channelRegistered(ChannelHandlerContext ctx) throws Exception {
initChannel((C) ctx.channel());
ctx.pipeline().remove(this);
ctx.fireChannelRegistered();
}
public ChannelPipeline addLast(EventExecutorGroup group, final String name, ChannelHandler handler) {
synchronized (this) {
checkDuplicateName(name); // 检查此 handler 是否有重复的名字
AbstractChannelHandlerContext newCtx = new DefaultChannelHandlerContext(this, group, name, handler);
addLast0(name, newCtx);
}
return this;
}
DefaultChannelHandlerContext(DefaultChannelPipeline pipeline, EventExecutor executor, String name, ChannelHandler handler) {
super(pipeline, executor, name, isInbound(handler), isOutbound(handler));
if(handler == null) {
throw new NullPointerException("handler");
} else {
this.handler = handler;
}
}
Netty的事件分为Inbound事件和Outbound事件分别代表管道中两个方向的数据流向;pipeline管道中维护的双向链表的节点也根据DefaultChannelHandlerContext实例的inbound属性和outbound属性分为inbound节点和outbound节点,输入时间会依次经过inbound节点的处理,输出事件会依次经过outbound节点的处理;
读写数据流依次经过相应节点处理,一个节点处理完后会调用ChannelHandlerContext.fireChannelRegistered()传递到下一个节点
read() or write()
Channel or ChannelHandlerContext
|
+---------------------------------------------------+---------------+
| ChannelPipeline | |
| \|/ |
| +---------------------+ +-----------+----------+ |
| | Inbound Handler N | | Outbound Handler 1 | |
| +----------+----------+ +-----------+----------+ |
| /|\ | |
| | \|/ |
| +----------+----------+ +-----------+----------+ |
| | Inbound Handler N-1 | | Outbound Handler 2 | |
| +----------+----------+ +-----------+----------+ |
| /|\ . |
| . . |
| ChannelHandlerContext.fireIN_EVT() ChannelHandlerContext.OUT_EVT()|
| [ method call] [method call] |
| . . |
| . \|/ |
| +----------+----------+ +-----------+----------+ |
| | Inbound Handler 2 | | Outbound Handler M-1 | |
| +----------+----------+ +-----------+----------+ |
| /|\ | |
| | \|/ |
| +----------+----------+ +-----------+----------+ |
| | Inbound Handler 1 | | Outbound Handler M | |
| +----------+----------+ +-----------+----------+ |
| /|\ | |
+---------------+-----------------------------------+---------------+
| \|/
+---------------+-----------------------------------+---------------+
| | | |
| [ Socket.read() ] [ Socket.write() ] |
| |
| Netty Internal I/O Threads (Transport Implementation) |
+-------------------------------------------------------------------+
outbound事件是请求事件,Channel发起具体的事件最终通过Unsafe底层进行处理,数据传输的方向是tail -> head;
在自定义handle中通过ctx.write()方法向通道中写入数据
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf = (ByteBuf)msg;
ctx.write(buf);
}
public ChannelFuture write(Object msg) {
return this.write(msg, this.newPromise());
}
public ChannelFuture write(Object msg, ChannelPromise promise) {
if(msg == null) {
throw new NullPointerException("msg");
} else {
try {
if(this.isNotValidPromise(promise, true)) {
ReferenceCountUtil.release(msg);
return promise;
}
} catch (RuntimeException var4) {
ReferenceCountUtil.release(msg);
throw var4;
}
this.write(msg, false, promise);
return promise;
}
}
private void write(Object msg, boolean flush, ChannelPromise promise) {
AbstractChannelHandlerContext next = this.findContextOutbound();
Object m = this.pipeline.touch(msg, next);
EventExecutor executor = next.executor();
if(executor.inEventLoop()) {
if(flush) {
next.invokeWriteAndFlush(m, promise);
} else {
next.invokeWrite(m, promise);
}
} else {
Object task;
if(flush) {
task = AbstractChannelHandlerContext.WriteAndFlushTask.newInstance(next, m, promise);
} else {
task = AbstractChannelHandlerContext.WriteTask.newInstance(next, m, promise);
}
safeExecute(executor, (Runnable)task, promise, m);
}
}
private void invokeWrite(Object msg, ChannelPromise promise) {
if(this.invokeHandler()) {
this.invokeWrite0(msg, promise);
} else {
this.write(msg, promise);
}
}
private void invokeWrite0(Object msg, ChannelPromise promise) {
try {
((ChannelOutboundHandler)this.handler()).write(this, msg, promise);
} catch (Throwable var4) {
notifyOutboundHandlerException(var4, promise);
}
}
handler.write() -> context.write() -> context.findContextOutbound -> next.invokeWrite -> handler.write -> context.write()
outbound事件传播机制
Outbound 事件是请求事件(由write方法或者connect方法发起一个请求, 并最终由 unsafe 处理这个请求),,Outbound 事件的发起者是 Channel,Outbound 事件的处理者是 unsafe;
Outbound 事件在 Pipeline 中的传输方向是 tail -> head.
在 ChannelHandler 中处理事件时, 如果这个 Handler 不是最后一个 Hnalder, 则需要调用 ctx.xxx (例如 ctx.connect) 将此事件继续传播下去. 如果不这样做, 那么此事件的传播会提前终止.如StringDecoder是最后一个Handler则将作为事件传播的终点不再向下传播;
Outbound 事件流: Context.xxx -> Connect.findContextOutbound -> nextContext.invokeXxx -> nextHandler.xxx -> nextContext.xxx
public ChannelPipeline fireChannelActive() {
head.fireChannelActive();
if (channel.config().isAutoRead()) {
channel.read();
}
return this;
}
public ChannelHandlerContext fireChannelActive() {
final AbstractChannelHandlerContext next = findContextInbound();
EventExecutor executor = next.executor();
...
next.invokeChannelActive();
...
return this;
}
private void invokeChannelActive() {
try {
((ChannelInboundHandler) handler()).channelActive(this);
} catch (Throwable t) {
notifyHandlerException(t);
}
}
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelActive();
}
pipeline.fireChannelXxx() -> ctx.fireChannelXxx() -> findContextInbound() -> ctx.invokeChannelXxx() -> handler.channelXxx() -> ctx.fireChannelXxx()
inbound事件传播机制
Inbound事件是通知型事件,事件由底层程序产生,通知上层应用程序,Inbound 事件在 Pipeline 中传输方向是 head -> tail;
Inbound 事件的处理者是 Channel, 如果用户没有实现自定义的处理方法, 那么Inbound 事件默认的处理者是 TailContext, 并且其处理方法是空实现.
在 ChannelHandler 中处理事件时, 如果这个 Handler 不是最后一个 Hnalder, 则需要调用 ctx.fireChannelXxx (例如 ctx.fireChannelActive) 将此事件继续传播下去. 如果不这样做, 那么此事件的传播会提前终止.
Outbound 事件流: Context.fireChannelXxx -> Connect.findContextInbound -> nextContext.invokeChannelXxx -> nextHandler.ChannelXxx -> nextContext.fireChannelXxx
pipeline是事件传播的管道,内部维护着一个双向链表,链表节点分为inbound类型和outbount类型;
输入事件比如read事件,数据流从链表的head到tail依次经过链表inbound类型节点的处理;
输出事件比如write事件,数据流从链表的tail到head依次经过链表outbound类型节点的处理;