Netty源码分析之ChannelHandler的添加与删除

ChannelHandler的添加

  一般用户会先添加ChannelInitializer这个Handler,通过这个handler获取channel对应的pipeline,将一系列的channelHandler添加到Pipeline上面。主要是通过调用pipeline的addLast方法进行添加。代码示例如下:

bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
    @Override
    public void initChannel(SocketChannel channel) throws Exception {
        channel.pipeline()
                .addLast(new LengthFieldBasedFrameDecoder(65536, 0, 4, 0, 0))
                .addLast(new RpcDecoder(RpcRequest.class))
                .addLast(new RpcEncoder(RpcResponse.class))
                .addLast(new RpcHandler(handlerMap));
    }
})
        .option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);

addLast方法流程:

1.判断是否重复添加

2.创建节点并添加到链表中

3.回调添加完成事件

public ChannelPipeline addLast(EventExecutorGroup executor, ChannelHandler... handlers) {
    if(handlers == null) {
        throw new NullPointerException("handlers");
    } else {
        ChannelHandler[] arr$ = handlers;
        int len$ = handlers.length;

        for(int i$ = 0; i$ < len$; ++i$) {
            ChannelHandler h = arr$[i$];
            if(h == null) {
                break;
            }

            this.addLast(executor, this.generateName(h), h);
        }

        return this;
    }
}
public ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
synchronized(this) {
this.checkDuplicateName(name);
DefaultChannelHandlerContext newCtx = new DefaultChannelHandlerContext(this, group, name, handler);
this.addLast0(name, newCtx);
return this;
}
}

  这里检查是否重复添加ChannelHandler,是通过checkDuplicateName,而这个方法的内部就是判断一个HashMap的key中是否有这个ChannelHandler的名字。

private void checkDuplicateName(String name) {
    if(this.name2ctx.containsKey(name)) {
        throw new IllegalArgumentException("Duplicate handler name: " + name);
    }
}

  如果没有重复,使用这个handler创建一个ChannelHandlerContext节点,这里传入group是null。

DefaultChannelHandlerContext(DefaultChannelPipeline pipeline, EventExecutorGroup group, String name, ChannelHandler handler) {
    super(pipeline, group, name, isInbound(handler), isOutbound(handler));
    if(handler == null) {
        throw new NullPointerException("handler");
    } else {
        this.handler = handler;
    }
}

  然后就是就是将channelHandler添加至pipeline中了,逻辑其实就是将一个新的节点添加到双向链表最后一个节点的前面。并且将channelHandlerContext的名字和实例放入到hashMap中。

private void addLast0(String name, AbstractChannelHandlerContext newCtx) {
    checkMultiplicity(newCtx);
    AbstractChannelHandlerContext prev = this.tail.prev;
    newCtx.prev = prev;
    newCtx.next = this.tail;
    prev.next = newCtx;
    this.tail.prev = newCtx;
    this.name2ctx.put(name, newCtx);
    this.callHandlerAdded(newCtx);
}

  最后节点添加完成进行回调callHandlerAdded,最后会调用handlerAdded这个方法,这个方法我们是可以进行重写的,可以在channelHandler添加到pipeline上之后处理一些事情。

private void callHandlerAdded(final ChannelHandlerContext ctx) {
    if(ctx.channel().isRegistered() && !ctx.executor().inEventLoop()) {
        ctx.executor().execute(new Runnable() {
            public void run() {
                DefaultChannelPipeline.this.callHandlerAdded0(ctx);
            }
        });
    } else {
        this.callHandlerAdded0(ctx);
    }
}
private void callHandlerAdded0(ChannelHandlerContext ctx) {
    try {
        ctx.handler().handlerAdded(ctx);
    } catch (Throwable var6) {
        boolean removed = false;

        try {
            this.remove((AbstractChannelHandlerContext)((AbstractChannelHandlerContext)ctx));
            removed = true;
        } catch (Throwable var5) {
            if(logger.isWarnEnabled()) {
                logger.warn("Failed to remove a handler: " + ctx.name(), var5);
            }
        }

        if(removed) {
            this.fireExceptionCaught(new ChannelPipelineException(ctx.handler().getClass().getName() + ".handlerAdded() has thrown an exception; removed.", var6));
        } else {
            this.fireExceptionCaught(new ChannelPipelineException(ctx.handler().getClass().getName() + ".handlerAdded() has thrown an exception; also failed to remove.", var6));
        }
    }

}

  

ChannelHandler的删除

使用场景:ChannelInitializer这个Handler最后会将自己删除;.权限校验,第一个数据包会检验权限,如果不满足直接关闭当前的channel,如果满足将权限校验移除。

流程:

1.找到节点

2.链表的删除

3.回调删除Handler事件

private AbstractChannelHandlerContext remove(final AbstractChannelHandlerContext ctx) {
    assert ctx != this.head && ctx != this.tail;

    AbstractChannelHandlerContext context;
    Future future;
    synchronized(this) {
        if(!ctx.channel().isRegistered() || ctx.executor().inEventLoop()) {
            this.remove0(ctx);
            return ctx;
        }

        future = ctx.executor().submit(new Runnable() {
            public void run() {
                DefaultChannelPipeline var1 = DefaultChannelPipeline.this;
                synchronized(DefaultChannelPipeline.this) {
                    DefaultChannelPipeline.this.remove0(ctx);
                }
            }
        });
        context = ctx;
    }

    waitForFuture(future);
    return context;
}
void remove0(AbstractChannelHandlerContext ctx) {
AbstractChannelHandlerContext prev = ctx.prev;
AbstractChannelHandlerContext next = ctx.next;
prev.next = next;
next.prev = prev;
this.name2ctx.remove(ctx.name());
this.callHandlerRemoved(ctx);
}

  最后也会回调handlerRemoved方法,该方法会在handler从pipeline中删除时被调用。这里的handlerAdded和handlerRemoved都是对channelHandler生命周期的一个监听方法。

猜你喜欢

转载自www.cnblogs.com/xiaobaituyun/p/10803823.html