invokeHandlerAddedIfNeeded() 方法详解
方法概述
pipeline.invokeHandlerAddedIfNeeded() 是在 register0() 方法中调用的,它的作用是触发 pipeline 中所有 handler 的 handlerAdded() 回调方法,特别是会执行 ChannelInitializer 的初始化逻辑,将我们自定义的 handlers 真正添加到 pipeline 中。
为什么需要这个方法?
问题背景
在 Channel 创建和初始化过程中,我们会向 pipeline 添加 handlers,但这些 handlers 的 handlerAdded() 方法不能立即调用,因为:
- Channel 还没有注册到 EventLoop:handler 的回调需要在正确的线程(EventLoop 线程)中执行
- Pipeline 可能还在构建中:过早调用可能导致状态不一致
- 需要延迟初始化:特别是
ChannelInitializer,它需要等到 register 完成后才能执行
解决方案
Netty 使用了一个 PendingHandlerCallback 链表来保存待执行的回调任务,等到合适的时机(register 完成后)再统一执行。
源码分析
1. 入口方法
// DefaultChannelPipeline
final void invokeHandlerAddedIfNeeded() {
assert channel.eventLoop().inEventLoop();
if (firstRegistration) {
firstRegistration = false;
// 调用所有待处理的 handlerAdded 回调
callHandlerAddedForAllHandlers();
}
}
关键点:
assert channel.eventLoop().inEventLoop():确保在 EventLoop 线程中执行firstRegistration:标记是否是首次注册,只在首次注册时执行- 执行后将
firstRegistration设为 false,避免重复执行
2. 核心方法:callHandlerAddedForAllHandlers()
private void callHandlerAddedForAllHandlers() {
final PendingHandlerCallback pendingHandlerCallbackHead;
synchronized (this) {
assert !registered;
// 标记 pipeline 已经注册
registered = true;
// 获取待处理的回调链表头
pendingHandlerCallbackHead = this.pendingHandlerCallbackHead;
// 清空链表,因为马上要执行了
this.pendingHandlerCallbackHead = null;
}
// 遍历链表,执行所有待处理的回调
PendingHandlerCallback task = pendingHandlerCallbackHead;
while (task != null) {
task.execute(); // 执行回调
task = task.next; // 移动到下一个
}
}
执行流程:
- 加锁获取待处理回调链表
- 标记 pipeline 为已注册状态
- 清空链表(因为马上要执行)
- 遍历链表,依次执行每个回调
3. PendingHandlerCallback 是什么?
这是一个内部抽象类,用于封装待执行的回调任务:
private abstract static class PendingHandlerCallback implements Runnable {
final AbstractChannelHandlerContext ctx;
PendingHandlerCallback next;
PendingHandlerCallback(AbstractChannelHandlerContext ctx) {
this.ctx = ctx;
}
abstract void execute();
}
它有两个具体实现:
(1) PendingHandlerAddedTask
private final class PendingHandlerAddedTask extends PendingHandlerCallback {
PendingHandlerAddedTask(AbstractChannelHandlerContext ctx) {
super(ctx);
}
@Override
public void run() {
callHandlerAdded0(ctx);
}
@Override
void execute() {
EventExecutor executor = ctx.executor();
if (executor.inEventLoop()) {
// 如果在正确的线程中,直接调用
callHandlerAdded0(ctx);
} else {
try {
// 否则提交到正确的线程中执行
executor.execute(this);
} catch (RejectedExecutionException e) {
// 处理异常...
remove0(ctx);
}
}
}
}
(2) PendingHandlerRemovedTask
private final class PendingHandlerRemovedTask extends PendingHandlerCallback {
// 类似的结构,用于处理 handlerRemoved 回调
}
4. 何时创建 PendingHandlerCallback?
在向 pipeline 添加 handler 时:
// DefaultChannelPipeline
@Override
public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
final AbstractChannelHandlerContext newCtx;
synchronized (this) {
// 检查是否重复添加等...
// 创建新的 context 节点
newCtx = newContext(group, filterName(name, handler), handler);
// 添加到链表中
addLast0(newCtx);
// 如果还没有注册,创建 PendingHandlerCallback
if (!registered) {
newCtx.setAddPending();
// 将回调任务添加到待处理链表中
callHandlerCallbackLater(newCtx, true);
return this;
}
EventExecutor executor = newCtx.executor();
if (!executor.inEventLoop()) {
// 如果不在正确的线程中,延迟执行
callHandlerAddedInEventLoop(newCtx, executor);
return this;
}
}
// 如果已经注册且在正确的线程中,立即调用
callHandlerAdded0(newCtx);
return this;
}
关键逻辑:
if (!registered) {
// Pipeline 还没注册,创建待处理任务
callHandlerCallbackLater(newCtx, true);
}
5. callHandlerCallbackLater() 方法
private void callHandlerCallbackLater(AbstractChannelHandlerContext ctx, boolean added) {
assert !registered;
PendingHandlerCallback task = added ?
new PendingHandlerAddedTask(ctx) :
new PendingHandlerRemovedTask(ctx);
// 添加到链表尾部
if (pendingHandlerCallbackHead == null) {
pendingHandlerCallbackHead = task;
} else {
PendingHandlerCallback current = pendingHandlerCallbackHead;
while (current.next != null) {
current = current.next;
}
current.next = task;
}
}
构建一个单向链表,保存所有待执行的回调任务。
6. 最终执行:callHandlerAdded0()
private void callHandlerAdded0(final AbstractChannelHandlerContext ctx) {
try {
// 调用 handler 的 handlerAdded 方法
ctx.callHandlerAdded();
} catch (Throwable t) {
// 异常处理...
}
}
// AbstractChannelHandlerContext
final void callHandlerAdded() throws Exception {
if (setAddComplete()) {
handler().handlerAdded(this);
}
}
ChannelInitializer 的特殊作用
为什么需要 ChannelInitializer?
在实际使用中,我们通常这样写:
bootstrap.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline()
.addLast(new LoggingHandler())
.addLast(new MyHandler());
}
});
ChannelInitializer 的工作原理
public abstract class ChannelInitializer<C extends Channel> extends ChannelInboundHandlerAdapter {
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
if (ctx.channel().isRegistered()) {
// 如果 channel 已经注册,立即初始化
if (initChannel(ctx)) {
// 初始化完成后,移除自己
removeState(ctx);
}
}
}
private boolean initChannel(ChannelHandlerContext ctx) throws Exception {
if (initMap.add(ctx)) {
try {
// 调用我们重写的 initChannel 方法
initChannel((C) ctx.channel());
} catch (Throwable cause) {
exceptionCaught(ctx, cause);
} finally {
// 从 pipeline 中移除 ChannelInitializer
ChannelPipeline pipeline = ctx.pipeline();
if (pipeline.context(this) != null) {
pipeline.remove(this);
}
}
return true;
}
return false;
}
// 这是我们需要实现的抽象方法
protected abstract void initChannel(C ch) throws Exception;
}
执行流程:
handlerAdded()被调用(在invokeHandlerAddedIfNeeded()中)- 检查 channel 是否已注册
- 调用我们重写的
initChannel()方法 - 在
initChannel()中,我们添加真正的业务 handlers - 最后,ChannelInitializer 将自己从 pipeline 中移除
完整的时序图
Channel 创建
↓
init(channel) - 添加 ChannelInitializer 到 pipeline
↓
此时 pipeline: head -> ChannelInitializer -> tail
↓
因为 !registered,创建 PendingHandlerAddedTask
↓
register 操作
↓
doRegister() - 注册到 Selector
↓
invokeHandlerAddedIfNeeded()
↓
callHandlerAddedForAllHandlers()
↓
遍历 PendingHandlerCallback 链表
↓
callHandlerAdded0(ctx)
↓
ChannelInitializer.handlerAdded()
↓
initChannel(channel) - 我们重写的方法
↓
添加真正的 handlers: LoggingHandler, MyHandler
↓
移除 ChannelInitializer
↓
最终 pipeline: head -> LoggingHandler -> MyHandler -> tail
实际例子
服务端启动代码
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) {
ChannelPipeline p = ch.pipeline();
p.addLast(new LoggingHandler(LogLevel.INFO));
p.addLast(new EchoServerHandler());
}
});
执行过程
-
Channel 创建时:
- Pipeline:
head -> ChannelInitializer -> tail - ChannelInitializer 被添加,但
handlerAdded()还没调用 - 创建
PendingHandlerAddedTask并加入链表
- Pipeline:
-
register0() 执行时:
- 调用
doRegister()完成底层注册 - 调用
invokeHandlerAddedIfNeeded() - 执行
PendingHandlerAddedTask - 触发
ChannelInitializer.handlerAdded()
- 调用
-
ChannelInitializer.handlerAdded() 中:
- 调用我们重写的
initChannel()方法 - 添加
LoggingHandler和EchoServerHandler - 移除
ChannelInitializer自己
- 调用我们重写的
-
最终结果:
- Pipeline:
head -> LoggingHandler -> EchoServerHandler -> tail
- Pipeline:
关键设计思想
1. 延迟初始化
不在添加 handler 时立即调用 handlerAdded(),而是等到 register 完成后再调用,确保:
- Channel 已经和 EventLoop 关联
- 在正确的线程中执行
- Pipeline 处于稳定状态
2. 回调链表
使用 PendingHandlerCallback 链表保存待执行的回调,支持:
- 多个 handler 的批量初始化
- 保持添加顺序
- 统一的执行时机
3. ChannelInitializer 模式
通过 ChannelInitializer 这个特殊的 handler:
- 提供了优雅的 API 来配置 pipeline
- 自动完成初始化后移除自己
- 避免了手动管理 pipeline 的复杂性
4. 线程安全
通过 synchronized 和 inEventLoop() 检查,确保:
- 回调链表的线程安全访问
- 回调在正确的线程中执行
- 避免并发问题
总结
invokeHandlerAddedIfNeeded() 方法的核心作用:
- 触发时机:在 Channel 注册完成后,doRegister() 之后立即调用
- 主要功能:执行所有待处理的
handlerAdded()回调 - 关键作用:触发 ChannelInitializer 的初始化,完成 pipeline 的最终构建
- 设计精妙:通过延迟回调机制,确保在正确的时机、正确的线程中完成初始化
这个方法是 Netty pipeline 构建过程中的关键环节,它将我们在启动代码中配置的 handlers 真正添加到 pipeline 中,使得整个处理链条得以建立!
3610



被折叠的 条评论
为什么被折叠?



