Netty之ChannelPipeline(二)移除ChannelHandler

Sachi ·
更新时间:2024-11-14
· 674 次阅读

上次说了添加,这次看看移除。
remove(ChannelHandler handler)方法,从pipeline移除指定ChannelHandler对象

@Override public final ChannelPipeline remove(ChannelHandler handler) { remove(getContextOrDie(handler)); return this; }

getContextOrDie(ChannelHandler handler)方法获得相应AbstractChannelHandlerContext节点:

private AbstractChannelHandlerContext getContextOrDie(ChannelHandler handler) { AbstractChannelHandlerContext ctx = (AbstractChannelHandlerContext) context(handler); if (ctx == null) { //若得不到节点,抛异常 throw new NoSuchElementException(handler.getClass().getName()); } else { return ctx; } } @Override public final ChannelHandlerContext context(ChannelHandler handler) { if (handler == null) { throw new NullPointerException("handler"); } AbstractChannelHandlerContext ctx = head.next; // 循环,获得指定 ChannelHandler 对象的节点 for (;;) { if (ctx == null) { return null; } if (ctx.handler() == handler) { // ChannelHandler 相等 return ctx; } ctx = ctx.next; } }

remove(AbstractChannelHandlerContext ctx) 方法,移除指定 AbstractChannelHandlerContext 节点:

private AbstractChannelHandlerContext remove(final AbstractChannelHandlerContext ctx) { assert ctx != head && ctx != tail; synchronized (this) { //防止多线程并发操作 pipeline 底层的双向链表 // 移除节点 remove0(ctx); // If the registered is false it means that the channel was not registered on an eventloop yet. // In this case we remove the context from the pipeline and add a task that will call // ChannelHandler.handlerRemoved(...) once the channel is registered. if (!registered) { //Channel未注册 //添加PendingHandlerRemovedTask回调,在Channel注册完成后执行该回调。 callHandlerCallbackLater(ctx, false); return ctx; } EventExecutor executor = ctx.executor(); // 不在 EventLoop 的线程中。 if (!executor.inEventLoop()) { // 提交 EventLoop 中, executor.execute(new Runnable() { @Override public void run() { //执行回调 ChannelHandler removed 事件 callHandlerRemoved0(ctx); } }); return ctx; } } // 回调 ChannelHandler removed 事件 callHandlerRemoved0(ctx); return ctx; }

remove0(AbstractChannelHandlerContext ctx) 方法,从 pipeline 移除指定的 AbstractChannelHandlerContext 节点。

private static void remove0(AbstractChannelHandlerContext ctx) { // 获得移除节点的前后节点 AbstractChannelHandlerContext prev = ctx.prev; AbstractChannelHandlerContext next = ctx.next; // 前后节点互相指向 prev.next = next; next.prev = prev; }

callHandlerRemoved0(AbstractChannelHandlerContext) 方法,执行回调 ChannelHandler 移除完成( removed )事件:

private void callHandlerRemoved0(final AbstractChannelHandlerContext ctx) { // Notify the complete removal. try { try { // 回调 ChannelHandler 移除完成( removed )事件,释放ChannelHandler占用的资源(由于这个方法的执行在EventLoop线程内,所以要尽量避免执行时间过长) ctx.handler().handlerRemoved(ctx); } finally { // 设置 AbstractChannelHandlerContext 已移除 ctx.setRemoved(); } } catch (Throwable t) { fireExceptionCaught(new ChannelPipelineException( ctx.handler().getClass().getName() + ".handlerRemoved() has thrown an exception.", t)); } }

PendingHandlerRemovedTask 实现 PendingHandlerCallback 抽象类,用于回调移除 ChannelHandler 节点:

private final class PendingHandlerRemovedTask extends PendingHandlerCallback { PendingHandlerRemovedTask(AbstractChannelHandlerContext ctx) { super(ctx); } @Override public void run() { callHandlerRemoved0(ctx); } @Override void execute() { EventExecutor executor = ctx.executor(); // 在 EventLoop 的线程中,回调 ChannelHandler removed 事件 if (executor.inEventLoop()) { callHandlerRemoved0(ctx); } else { // 提交 EventLoop 中,执行回调 ChannelHandler removed 事件 try { executor.execute(this); } catch (RejectedExecutionException e) { if (logger.isWarnEnabled()) { logger.warn( "Can't invoke handlerRemoved() as the EventExecutor {} rejected it," + " removing handler {}.", executor, ctx.name(), e); } // 标记 AbstractChannelHandlerContext 为已移除 // remove0(...) was call before so just call AbstractChannelHandlerContext.setRemoved(). ctx.setRemoved(); } } } }
作者:究极机器



netty

需要 登录 后方可回复, 如果你还没有账号请 注册新账号