Netty源码分析第4章(pipeline)---->第3节: handler的删除
Netty源码分析第四章: pipeline
第三节: handler的删除
上一小节我们学习了添加handler的逻辑操作, 这一小节我们学习删除handler的相关逻辑
如果用户在业务逻辑中进行ctx.pipeline().remove(this)这样的写法, 或者ch.pipeline().remove(new SimpleHandler())这样的写法, 则就是对handler进行删除, 我们学习过添加handler的逻辑, 所以对handler删除操作理解起来也会比较容易
我们首先跟到defaultChannelPipeline的remove(handler)的方法中:
public final ChannelPipeline remove(ChannelHandler handler) {
remove(getContextOrDie(handler));
return this;
}
方法体里有个remove()方法, 传入一个 getContextOrDie(handler) 参数, 这个 getContextOrDie(handler) , 其实就是根据handler拿到其包装类HandlerContext对象
我们跟到getContextPrDie这个方法中:
private AbstractChannelHandlerContext getContextOrDie(ChannelHandler handler) {
AbstractChannelHandlerContext ctx = (AbstractChannelHandlerContext) context(handler);
//代码省略
}
这里仍然会通过context(handler)方法去寻找, 再跟进去:
public final ChannelHandlerContext context(ChannelHandler handler) {
if (handler == null) {
throw new NullPointerException("handler");
}
//从头遍历节点
AbstractChannelHandlerContext ctx = head.next;
for (;;) {
if (ctx == null) {
return null;
}
//找到handler
if (ctx.handler() == handler) {
return ctx;
}
ctx = ctx.next;
}
}
这里我们看到寻找的方法也非常的简单, 就是从头结点开始遍历, 遍历到如果其包装的handler对象是传入的handler对象, 则返回找到的handlerContext
回到remove(handler)方法:
public final ChannelPipeline remove(ChannelHandler handler) {
remove(getContextOrDie(handler));
return this;
}
继续跟到remove方法中:
private AbstractChannelHandlerContext remove(final AbstractChannelHandlerContext ctx) { //当前删除的节点不能是head, 也不能是tail
assert ctx != head && ctx != tail; synchronized (this) {
//执行删除操作
remove0(ctx);
if (!registered) {
callHandlerCallbackLater(ctx, false);
return ctx;
} //回调删除handler事件
EventExecutor executor = ctx.executor();
if (!executor.inEventLoop()) {
executor.execute(new Runnable() {
@Override
public void run() {
callHandlerRemoved0(ctx);
}
});
return ctx;
}
}
callHandlerRemoved0(ctx);
return ctx;
}
首先要断言删除的节点不能是tail和head
然后通过remove0(ctx)进行实际的删除操作, 跟到remove0(ctx)中:
private static void remove0(AbstractChannelHandlerContext ctx) {
//当前节点的前置节点
AbstractChannelHandlerContext prev = ctx.prev;
//当前节点的后置节点
AbstractChannelHandlerContext next = ctx.next;
//前置节点的下一个节点设置为后置节点
prev.next = next;
//后置节点的上一个节点设置为前置节点
next.prev = prev;
}
这里的操作也非常简单, 做了一个指针移动的操作, 熟悉双向链表的小伙伴应该不会陌生, 删除节点逻辑大概如下图所示:
4-3-1
回到remove(ctx)方法:
private AbstractChannelHandlerContext remove(final AbstractChannelHandlerContext ctx) { //当前删除的节点不能是head, 也不能是tail
assert ctx != head && ctx != tail; synchronized (this) {
//执行删除操作
remove0(ctx);
if (!registered) {
callHandlerCallbackLater(ctx, false);
return ctx;
} //回调删除handler事件
EventExecutor executor = ctx.executor();
if (!executor.inEventLoop()) {
executor.execute(new Runnable() {
@Override
public void run() {
callHandlerRemoved0(ctx);
}
});
return ctx;
}
}
callHandlerRemoved0(ctx);
return ctx;
}
我们继续往下看, 如果当前线程不是eventLoop线程则将回调删除事件封装成task放在taskQueue中让eventLoop线程进行执行, 否则, 则直接执行回调删除事件
跟到callHandlerRemoved0(ctx)方法中:
private void callHandlerRemoved0(final AbstractChannelHandlerContext ctx) {
try {
try {
//调用handler的handlerRemoved方法
ctx.handler().handlerRemoved(ctx);
} finally {
//将当前节点状态设置为已移除
ctx.setRemoved();
}
} catch (Throwable t) {
fireExceptionCaught(new ChannelPipelineException(
ctx.handler().getClass().getName() + ".handlerRemoved() has thrown an exception.", t));
}
}
与添加handler的逻辑一样, 这里会调用当前handler的handlerRemoved方法, 如果用户没有重写该方法, 则会调用其父类的方法, 方法体在ChannelHandlerAdapter类中有定义, 我们跟进去
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { }
同添加handler一样, 也是一个空实现, 这里用户可以通过重写来添加自己需要的逻辑
以上就是删除handler的相关操作
Netty源码分析第4章(pipeline)---->第3节: handler的删除的更多相关文章
- Netty源码分析第4章(pipeline)---->第2节: handler的添加
Netty源码分析第四章: pipeline 第二节: Handler的添加 添加handler, 我们以用户代码为例进行剖析: .childHandler(new ChannelInitialize ...
- Netty源码分析第4章(pipeline)---->第4节: 传播inbound事件
Netty源码分析第四章: pipeline 第四节: 传播inbound事件 有关于inbound事件, 在概述中做过简单的介绍, 就是以自己为基准, 流向自己的事件, 比如最常见的channelR ...
- Netty源码分析第4章(pipeline)---->第5节: 传播outbound事件
Netty源码分析第五章: pipeline 第五节: 传播outBound事件 了解了inbound事件的传播过程, 对于学习outbound事件传输的流程, 也不会太困难 在我们业务代码中, 有可 ...
- Netty源码分析第4章(pipeline)---->第6节: 传播异常事件
Netty源码分析第四章: pipeline 第6节: 传播异常事件 讲完了inbound事件和outbound事件的传输流程, 这一小节剖析异常事件的传输流程 首先我们看一个最最简单的异常处理的场景 ...
- Netty源码分析第4章(pipeline)---->第7节: 前章节内容回顾
Netty源码分析第四章: pipeline 第七节: 前章节内容回顾 我们在第一章和第三章中, 遗留了很多有关事件传输的相关逻辑, 这里带大家一一回顾 首先看两个问题: 1.在客户端接入的时候, N ...
- Netty源码分析第4章(pipeline)---->第1节: pipeline的创建
Netty源码分析第四章: pipeline 概述: pipeline, 顾名思义, 就是管道的意思, 在netty中, 事件在pipeline中传输, 用户可以中断事件, 添加自己的事件处理逻辑, ...
- Netty源码分析第5章(ByteBuf)---->第10节: SocketChannel读取数据过程
Netty源码分析第五章: ByteBuf 第十节: SocketChannel读取数据过程 我们第三章分析过客户端接入的流程, 这一小节带大家剖析客户端发送数据, Server读取数据的流程: 首先 ...
- Netty源码分析第5章(ByteBuf)---->第4节: PooledByteBufAllocator简述
Netty源码分析第五章: ByteBuf 第四节: PooledByteBufAllocator简述 上一小节简单介绍了ByteBufAllocator以及其子类UnPooledByteBufAll ...
- Netty源码分析第5章(ByteBuf)---->第5节: directArena分配缓冲区概述
Netty源码分析第五章: ByteBuf 第五节: directArena分配缓冲区概述 上一小节简单分析了PooledByteBufAllocator中, 线程局部缓存和arean的相关逻辑, 这 ...
随机推荐
- 20165318 2017-2018-2 《Java程序设计》第七周学习总结
20165318 2017-2018-2 <Java程序设计>第七周学习总结 目录 学习过程遇到的问题及总结 教材学习内容总结 第11章 JDBC与MySQL数据库 错题总结 第五周错题总 ...
- 【bzoj 4154】[Ipsc2015]Generating Synergy
题目 大概已经掌握熟练码出\(kdt\)的技能了 发现距离子树根节点\(x\)不超过\(l\)的点可以用两种方式来限制,首先\(dfs\)序在\([dfn_x,dfn_x+sum_x)\)中,深度自然 ...
- Hive学习之路 (十)Hive的高级操作
一.负责数据类型 1.array 现有数据如下: 1 huangbo guangzhou,xianggang,shenzhen a1:30,a2:20,a3:100 beijing,112233,13 ...
- linux 字体 设置 en_US.UTF-8
设置:localectl set-local LANG=en_US.UTF-8 查看: localectl list-locales
- 4、JVM-虚拟机性能监控与故障处理工具
前言: Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的“高墙”,墙外面的人想进去,墙里面的人却想出来. 4.1.概述 给一个系统定位问题的时候,知识.经验是关键基础,数据是依据,工具是 ...
- 造成MySQL全表扫描的原因
全表扫描是数据库搜寻表的每一条记录的过程,直到所有符合给定条件的记录返回为止.通常在数据库中,对无索引的表进行查询一般称为全表扫描:然而有时候我们即便添加了索引,但当我们的SQL语句写的不合理的时候也 ...
- Python自动化之clean方法前端调用clean方法的错误
obj.non_field_errors.0 源代码: NON_FIELD_ERRORS = '__all__' 如果在前端写 obj.errors.__all__.0直接就会报错 所以经过尝试得知, ...
- JavaScript 空位补零实现代码
实现一: 复制代码代码如下: /* 平淡无奇法 */ function pad(num, n) { var i = (num + "").length; while(i++ < ...
- ORA-28000 账号被锁定的解决办法
ORA-28000 账号被锁定的解决办法 错误场景:当使用sqlplus进行登录时报错:ORA-28000 账号被锁定.错误原因:由于oracle 11g 在默认在default概要文件中设置了密码最 ...
- js array数组对象操作方法汇总
--------------------------更新自2018.6.11 js 数组对象操作方法如下: 1. 创建数组 var array1 = [1,2] //方法一 var array2 = ...