Netty源码分析---netty-init()方法解析

Netty架构篇 - Bootstrap、ServerBootstrap 本文主要分析Bootstrap、ServerBootstrap的相关方法的底层源码。 阅读详情

ChannelInitializer 完整工作原理详解

目录

  1. ChannelInitializer 概述
  2. ServerBootstrap.init() 方法详解
  3. ChannelInitializer 执行流程
  4. callHandlerAddedForAllHandlers() 机制
  5. 完整时序图
  6. 总结

一、ChannelInitializer 概述

1.1 什么是 ChannelInitializer?

ChannelInitializer 是一个特殊的 ChannelHandler,它的作用是:

  • 延迟初始化:在 channel 注册到 EventLoop 后才执行真正的初始化逻辑
  • 一次性使用:执行完 initChannel() 后会自动从 pipeline 中移除
  • 简化配置:提供一个统一的地方来配置 pipeline

1.2 为什么需要 ChannelInitializer?

问题场景
// 在 init() 方法中
ChannelPipeline p = channel.pipeline();

// ❌ 问题:此时 channel 还没有注册到 EventLoop
// 如果直接添加 handler,某些依赖 EventLoop 的操作会失败
p.addLast(new LoggingHandler());
p.addLast(new ServerBootstrapAcceptor(...)); // 这个 handler 需要 EventLoop

// ✅ 解决方案:使用 ChannelInitializer 延迟初始化
p.addLast(new ChannelInitializer<Channel>() {
    @Override
    public void initChannel(Channel ch) {
        // 这里的代码会在 channel 注册到 EventLoop 后执行
        ch.pipeline().addLast(new LoggingHandler());
        ch.pipeline().addLast(new ServerBootstrapAcceptor(...));
    }
});

二、ServerBootstrap.init() 方法详解

2.1 方法调用时机

这个方法在 initAndRegister() 中被调用:

final ChannelFuture initAndRegister() {
    Channel channel = null;
    try {
        // 1. 创建 NioServerSocketChannel 实例
        channel = channelFactory.newChannel();
        // 2. 初始化 channel(就是这个 init 方法)
        init(channel);
    } catch (Throwable t) {
        // ...
    }
    // 3. 注册到 EventLoop
    ChannelFuture regFuture = config().group().register(channel);
    return regFuture;
}

2.2 init() 方法完整源码分析

@Override
void init(Channel channel) throws Exception {
    // ==================== 第一部分:设置 ServerSocketChannel 的选项和属性 ====================
    
    // 1. 获取用户配置的 options(如 SO_BACKLOG 等)
    final Map<ChannelOption<?>, Object> options = options0();
    synchronized (options) {
        // 设置到 channel 的 config 中
        setChannelOptions(channel, options, logger);
    }
    
    // 2. 获取用户配置的 attributes
    final Map<AttributeKey<?>, Object> attrs = attrs0();
    synchronized (attrs) {
        for (Entry<AttributeKey<?>, Object> e: attrs.entrySet()) {
            @SuppressWarnings("unchecked")
            AttributeKey<Object> key = (AttributeKey<Object>) e.getKey();
            // 设置到 channel 的属性中
            channel.attr(key).set(e.getValue());
        }
    }

    
    // ==================== 第二部分:配置 ServerSocketChannel 的 Pipeline ====================
    
    // 3. 获取 channel 的 pipeline
    ChannelPipeline p = channel.pipeline();
    
    // 4. 保存 child 相关的配置(这些是给客户端连接用的)
    final EventLoopGroup currentChildGroup = childGroup;           // worker 线程组
    final ChannelHandler currentChildHandler = childHandler;       // 客户端 handler
    final Entry<ChannelOption<?>, Object>[] currentChildOptions;   // 客户端 options
    final Entry<AttributeKey<?>, Object>[] currentChildAttrs;      // 客户端 attributes
    
    synchronized (childOptions) {
        currentChildOptions = childOptions.entrySet().toArray(newOptionArray(0));
    }
    synchronized (childAttrs) {
        currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(0));
    }
    
    // ==================== 第三部分:向 Pipeline 添加 ChannelInitializer ====================
    
    // 5. 添加一个 ChannelInitializer 到 pipeline
    p.addLast(new ChannelInitializer<Channel>() {
        @Override
        public void initChannel(final Channel ch) throws Exception {
            final ChannelPipeline pipeline = ch.pipeline();
            
            // 5.1 添加用户配置的 handler(通过 .handler() 方法配置的)
            ChannelHandler handler = config.handler();
            if (handler != null) {
                pipeline.addLast(handler);
            }
            
            // 5.2 异步添加 ServerBootstrapAcceptor
            // 为什么要异步?因为此时可能还有其他初始化任务在执行
            ch.eventLoop().execute(new Runnable() {
                @Override
                public void run() {
                    // 添加接收器 handler,用于处理客户端连接
                    pipeline.addLast(new ServerBootstrapAcceptor(
                        ch, 
                        currentChildGroup,      // worker 线程组
                        currentChildHandler,    // 客户端 handler
                        currentChildOptions,    // 客户端 options
                        currentChildAttrs       // 客户端 attributes
                    ));
                }
            });
        }
    });
}


三、ChannelInitializer 执行流程

3.1 完整执行流程

步骤 1:添加到 Pipeline(init 阶段)
// ServerBootstrap.init() 方法中
p.addLast(new ChannelInitializer<Channel>() {
    @Override
    public void initChannel(final Channel ch) throws Exception {
        // 这里的代码会在 channel 注册到 EventLoop 后执行
    }
});

此时 Pipeline 状态:

head <-> ChannelInitializer <-> tail
步骤 2:Channel 注册到 EventLoop(register 阶段)
// AbstractChannel.register0() 方法
private void register0(ChannelPromise promise) {
    try {
        // 1. 执行 JDK 底层的注册
        doRegister();
        
        // 2. 标记为已注册
        registered = true;
        
        // 3. ⭐ 关键:调用 pipeline.invokeHandlerAddedIfNeeded()
        pipeline.invokeHandlerAddedIfNeeded();
        
        // 4. 设置 promise 成功
        safeSetSuccess(promise);
        
        // 5. 触发 channelRegistered 事件
        pipeline.fireChannelRegistered();
        
        // ...
    } catch (Throwable t) {
        // ...
    }
}
步骤 3:触发 ChannelInitializer.handlerAdded()
// DefaultChannelPipeline
final void invokeHandlerAddedIfNeeded() {
    assert channel.eventLoop().inEventLoop();
    if (firstRegistration) {
        firstRegistration = false;
        // 调用所有 handler 的 handlerAdded 方法
        callHandlerAddedForAllHandlers();
    }
}
步骤 4:ChannelInitializer.handlerAdded() 源码
// ChannelInitializer 类
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
    // 检查 channel 是否已注册
    if (ctx.channel().isRegistered()) {
        // ⭐ 如果已注册,立即执行 initChannel
        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;
}
步骤 5:执行我们的 initChannel 方法
// 我们在 ServerBootstrap.init() 中写的代码
@Override
public void initChannel(final Channel ch) throws Exception {
    final ChannelPipeline pipeline = ch.pipeline();
    
    // 1. 添加用户配置的 handler(如 LoggingHandler)
    ChannelHandler handler = config.handler();
    if (handler != null) {
        pipeline.addLast(handler);
    }
    
    // 2. 异步添加 ServerBootstrapAcceptor
    ch.eventLoop().execute(new Runnable() {
        @Override
        public void run() {
            pipeline.addLast(new ServerBootstrapAcceptor(
                ch, currentChildGroup, currentChildHandler, 
                currentChildOptions, currentChildAttrs));
        }
    });
}

执行后 Pipeline 状态:

head <-> LoggingHandler <-> ChannelInitializer <-> tail
                             (准备移除)
步骤 6:ChannelInitializer 自动移除
// ChannelInitializer.initChannel() 的 finally 块
finally {
    ChannelPipeline pipeline = ctx.pipeline();
    if (pipeline.context(this) != null) {
        // 从 pipeline 中移除自己
        pipeline.remove(this);
    }
}

移除后 Pipeline 状态:

head <-> LoggingHandler <-> tail
步骤 7:异步添加 ServerBootstrapAcceptor
// 之前提交的异步任务执行
ch.eventLoop().execute(new Runnable() {
    @Override
    public void run() {
        pipeline.addLast(new ServerBootstrapAcceptor(...));
    }
});

最终 Pipeline 状态:

head <-> LoggingHandler <-> ServerBootstrapAcceptor <-> tail

3.2 为什么要异步添加 ServerBootstrapAcceptor?

ch.eventLoop().execute(new Runnable() {
    @Override
    public void run() {
        pipeline.addLast(new ServerBootstrapAcceptor(...));
    }
});
原因分析
  1. 执行顺序保证

    • initChannel() 在 handlerAdded() 回调中执行
    • 此时可能还有其他 handler 的 handlerAdded() 等待执行
    • 异步提交确保所有初始化完成后再添加 Acceptor
  2. 避免递归调用

    • 如果同步添加,会立即触发 ServerBootstrapAcceptor.handlerAdded()
    • 可能导致调用栈过深
  3. 时机控制

    • ServerBootstrapAcceptor 是最后一个 handler
    • 应该在所有其他 handler 都就绪后再添加

四、callHandlerAddedForAllHandlers() 机制详解

4.1 "它们"指的是什么?

在调用 callHandlerAddedForAllHandlers() 时,pipeline 中的 handler 结构是这样的:

head <-> ChannelInitializer <-> tail

"它们"指的是:

  1. head(HeadContext)
  2. ChannelInitializer(我们添加的)
  3. tail(TailContext)

4.2 PendingHandlerCallback 机制

当我们调用 pipeline.addLast(handler) 时,如果 channel 还没有注册,handler 的 handlerAdded() 不会立即执行,而是会被包装成一个 PendingHandlerCallback 任务,加入到待处理队列中。

addLast() 方法源码
// DefaultChannelPipeline
@Override
public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
    final AbstractChannelHandlerContext newCtx;
    synchronized (this) {
        // 检查是否重复添加
        checkMultiplicity(handler);
        
        // 创建 HandlerContext
        newCtx = newContext(group, filterName(name, handler), handler);
        
        // 添加到 pipeline 链表中
        addLast0(newCtx);
        
        // ⭐ 关键:如果还没有注册,创建待处理任务
        if (!registered) {
            newCtx.setAddPending();
            // 创建 PendingHandlerAddedTask 并加入队列
            callHandlerCallbackLater(newCtx, true);
            return this;
        }
        
        // 如果已经注册,立即调用 handlerAdded
        EventExecutor executor = newCtx.executor();
        if (!executor.inEventLoop()) {
            callHandlerAddedInEventLoop(newCtx, executor);
            return this;
        }
    }
    // 调用 handlerAdded
    callHandlerAdded0(newCtx);
    return this;
}
callHandlerCallbackLater() 方法
// DefaultChannelPipeline
private void callHandlerCallbackLater(AbstractChannelHandlerContext ctx, boolean added) {
    assert !registered;
    
    // 创建待处理任务
    PendingHandlerCallback task = added ? 
        new PendingHandlerAddedTask(ctx) : 
        new PendingHandlerRemovedTask(ctx);
    
    // 加入到待处理队列
    PendingHandlerCallback pending = pendingHandlerCallbackHead;
    if (pending == null) {
        // 队列为空,设置为头节点
        pendingHandlerCallbackHead = task;
    } else {
        // 队列不为空,添加到队列尾部
        while (pending.next != null) {
            pending = pending.next;
        }
        pending.next = task;
    }
}

4.3 callHandlerAddedForAllHandlers() 源码

// DefaultChannelPipeline
private void callHandlerAddedForAllHandlers() {
    // pendingHandlerCallbackHead 是一个链表的头节点
    // 它保存了所有待处理的 handler 回调任务
    final PendingHandlerCallback pendingHandlerCallbackHead;
    
    synchronized (this) {
        assert !registered;
        
        // 标记为已注册
        registered = true;
        
        // 获取待处理的回调任务链表
        pendingHandlerCallbackHead = this.pendingHandlerCallbackHead;
        
        // 清空链表
        this.pendingHandlerCallbackHead = null;
    }
    
    // 遍历链表,执行所有待处理的回调
    PendingHandlerCallback task = pendingHandlerCallbackHead;
    while (task != null) {
        // 执行回调任务
        task.execute();
        task = task.next;
    }
}

4.4 PendingHandlerAddedTask 源码

// DefaultChannelPipeline 的内部类
private final class PendingHandlerAddedTask extends PendingHandlerCallback {
    
    PendingHandlerAddedTask(AbstractChannelHandlerContext ctx) {
        super(ctx);
    }
    
    @Override
    public void run() {
        // ⭐ 调用 handler 的 handlerAdded() 方法
        callHandlerAdded0(ctx);
    }
    
    @Override
    void execute() {
        EventExecutor executor = ctx.executor();
        if (executor.inEventLoop()) {
            // 在 EventLoop 线程中,直接执行
            callHandlerAdded0(ctx);
        } else {
            try {
                // 不在 EventLoop 线程中,提交任务
                executor.execute(this);
            } catch (RejectedExecutionException e) {
                // ...
            }
        }
    }
}
callHandlerAdded0() 方法
// DefaultChannelPipeline
private void callHandlerAdded0(final AbstractChannelHandlerContext ctx) {
    try {
        // ⭐⭐⭐ 调用 handler 的 handlerAdded() 方法
        ctx.callHandlerAdded();
    } catch (Throwable t) {
        // 异常处理
        boolean removed = false;
        try {
            remove0(ctx);
            ctx.callHandlerRemoved();
            removed = true;
        } catch (Throwable t2) {
            // ...
        }
        
        if (removed) {
            fireExceptionCaught(new ChannelPipelineException(
                ctx.handler().getClass().getName() +
                ".handlerAdded() has thrown an exception; removed.", t));
        } else {
            fireExceptionCaught(new ChannelPipelineException(
                ctx.handler().getClass().getName() +
                ".handlerAdded() has thrown an exception; also failed to remove.", t));
        }
    }
}
AbstractChannelHandlerContext.callHandlerAdded()
// AbstractChannelHandlerContext
final void callHandlerAdded() throws Exception {
    // 设置状态为 ADD_COMPLETE
    if (setAddComplete()) {
        // ⭐⭐⭐ 调用 handler 的 handlerAdded() 方法
        handler().handlerAdded(this);
    }
}

4.5 实际例子演示

假设我们在 init() 中添加了多个 handler:

@Override
void init(Channel channel) throws Exception {
    ChannelPipeline p = channel.pipeline();
    
    // 添加 handler1
    p.addLast(new MyHandler1());
    
    // 添加 ChannelInitializer
    p.addLast(new ChannelInitializer<Channel>() {
        @Override
        public void initChannel(Channel ch) {
            ch.pipeline().addLast(new LoggingHandler());
        }
    });
    
    // 添加 handler2
    p.addLast(new MyHandler2());
}

执行过程:

  1. init() 阶段(channel 未注册):
Pipeline: head <-> MyHandler1 <-> ChannelInitializer <-> MyHandler2 <-> tail

待处理队列:
PendingHandlerAddedTask(MyHandler1)
    ↓
PendingHandlerAddedTask(ChannelInitializer)
    ↓
PendingHandlerAddedTask(MyHandler2)
  1. register() 完成后,调用 callHandlerAddedForAllHandlers():
// 遍历待处理队列
task = PendingHandlerAddedTask(MyHandler1)
task.execute() -> MyHandler1.handlerAdded() 被调用

task = PendingHandlerAddedTask(ChannelInitializer)
task.execute() -> ChannelInitializer.handlerAdded() 被调用
              -> initChannel() 被调用
              -> LoggingHandler 被添加
              -> ChannelInitializer 被移除

task = PendingHandlerAddedTask(MyHandler2)
task.execute() -> MyHandler2.handlerAdded() 被调用
  1. 最终 Pipeline 状态:
head <-> MyHandler1 <-> LoggingHandler <-> MyHandler2 <-> tail

五、完整时序图

5.1 整体流程

1. ServerBootstrap.init(channel)
   │
   └─> pipeline.addLast(new ChannelInitializer() {...})
       │
       ├─> newContext(handler)  // 创建 Context
       ├─> addLast0(newCtx)     // 添加到 pipeline 链表
       │
       └─> if (!registered) {   // 如果还没注册
               // 创建待处理任务
               callHandlerCallbackLater(newCtx, true)
                   │
                   └─> new PendingHandlerAddedTask(ctx)
                       │
                       └─> 加入 pendingHandlerCallbackHead 队列
           }

此时状态:
- Pipeline: head <-> ChannelInitializer <-> tail
- 待处理队列: PendingHandlerAddedTask(ChannelInitializer)

═══════════════════════════════════════════════════════════

2. register(channel)
   │
   └─> AbstractChannel.register0()
       │
       ├─> doRegister()  // JDK 底层注册
       │
       └─> pipeline.invokeHandlerAddedIfNeeded()
           │
           └─> callHandlerAddedForAllHandlers()
               │
               ├─> 获取 pendingHandlerCallbackHead 队列
               │
               └─> while (task != null) {
                       task.execute()  // 执行待处理任务
                           │
                           └─> PendingHandlerAddedTask.execute()
                               │
                               └─> callHandlerAdded0(ctx)
                                   │
                                   └─> ctx.callHandlerAdded()
                                       │
                                       └─> handler().handlerAdded(this)
                                           │
                                           └─> ChannelInitializer.handlerAdded()
                                               │
                                               └─> initChannel(ctx)
                                                   │
                                                   ├─> 调用我们重写的 initChannel()
                                                   │   ├─> pipeline.addLast(LoggingHandler)
                                                   │   └─> eventLoop.execute(...)
                                                   │
                                                   └─> pipeline.remove(this)
                       
                       task = task.next  // 处理下一个任务
                   }

5.2 Pipeline 状态变化时序

时间线:
│
├─ 1. ServerBootstrap.init(channel)
│   └─ pipeline.addLast(new ChannelInitializer() {...})
│      Pipeline: head <-> ChannelInitializer <-> tail
│
├─ 2. register(channel) 
│   └─ AbstractChannel.register0()
│       ├─ doRegister() // JDK 底层注册
│       ├─ registered = true
│       └─ pipeline.invokeHandlerAddedIfNeeded()
│
├─ 3. invokeHandlerAddedIfNeeded()
│   └─ callHandlerAddedForAllHandlers()
│       └─ ChannelInitializer.handlerAdded()
│
├─ 4. ChannelInitializer.handlerAdded()
│   └─ initChannel(ctx)
│       ├─ 调用我们重写的 initChannel(channel)
│       │   ├─ pipeline.addLast(LoggingHandler)
│       │   └─ eventLoop.execute(() -> {
│       │       pipeline.addLast(ServerBootstrapAcceptor)
│       │   })
│       └─ pipeline.remove(this) // 移除 ChannelInitializer
│
├─ 5. Pipeline 状态变化
│   Pipeline: head <-> LoggingHandler <-> tail
│
└─ 6. 异步任务执行
    └─ pipeline.addLast(ServerBootstrapAcceptor)
       Pipeline: head <-> LoggingHandler <-> ServerBootstrapAcceptor <-> tail

六、总结

6.1 ChannelInitializer 的核心价值

  1. 延迟初始化:等到 channel 注册到 EventLoop 后再执行初始化逻辑
  2. 自动清理:执行完 initChannel() 后自动从 pipeline 中移除
  3. 简化代码:提供统一的初始化入口,代码更清晰
  4. 保证时机:确保初始化代码在正确的时机执行

6.2 执行时机总结

  • addLast(ChannelInitializer):在 init() 阶段
  • initChannel() 被调用:在 register() 完成后
  • ChannelInitializer 被移除:在 initChannel() 执行完后
  • ServerBootstrapAcceptor 被添加:异步执行,在所有初始化完成后

6.3 PendingHandlerCallback 机制总结

"它们"指的是:

  • Pipeline 中所有在 channel 注册前添加的 handler
  • 这些 handler 的 handlerAdded() 回调被包装成 PendingHandlerAddedTask
  • 存储在 pendingHandlerCallbackHead 链表中

执行机制:

  1. addLast(handler) 时,如果 channel 未注册,创建 PendingHandlerAddedTask 加入队列
  2. register() 完成后,调用 callHandlerAddedForAllHandlers()
  3. 遍历队列,依次执行每个 PendingHandlerAddedTask
  4. 每个任务会调用对应 handler 的 handlerAdded() 方法
  5. 对于 ChannelInitializer,它的 handlerAdded() 会触发 initChannel()

6.4 关键代码对比

不使用 ChannelInitializer(错误示例)
@Override
void init(Channel channel) throws Exception {
    ChannelPipeline p = channel.pipeline();
    
    // ❌ 此时 channel 还没注册到 EventLoop
    // 某些操作可能会失败
    p.addLast(new LoggingHandler());
    p.addLast(new ServerBootstrapAcceptor(...)); // 可能出错
}
使用 ChannelInitializer(正确示例)
@Override
void init(Channel channel) throws Exception {
    ChannelPipeline p = channel.pipeline();
    
    // ✅ 使用 ChannelInitializer 延迟初始化
    p.addLast(new ChannelInitializer<Channel>() {
        @Override
        public void initChannel(Channel ch) {
            // 这里执行时,channel 已经注册到 EventLoop
            ch.pipeline().addLast(new LoggingHandler());
            ch.eventLoop().execute(() -> {
                ch.pipeline().addLast(new ServerBootstrapAcceptor(...));
            });
        }
    });
}

6.5 ServerBootstrapAcceptor 的作用

这是一个非常重要的 handler,它的作用是处理客户端连接:

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
    // msg 就是客户端连接(NioSocketChannel)
    final Channel child = (Channel) msg;
    
    // 1. 给客户端连接添加 childHandler
    child.pipeline().addLast(childHandler);
    
    // 2. 设置客户端连接的 options
    setChannelOptions(child, childOptions, logger);
    
    // 3. 设置客户端连接的 attributes
    for (Entry<AttributeKey<?>, Object> e: childAttrs) {
        child.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());
    }
    
    // 4. 将客户端连接注册到 worker 线程组
    childGroup.register(child).addListener(new ChannelFutureListener() {
        @Override
        public void operationComplete(ChannelFuture future) throws Exception {
            if (!future.isSuccess()) {
                forceClose(child, future.cause());
            }
        }
    });
}

七、实际应用示例

ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
 .channel(NioServerSocketChannel.class)
 
 // 这些配置会在 init() 方法中被设置到 ServerSocketChannel
 .option(ChannelOption.SO_BACKLOG, 128)
 .attr(AttributeKey.valueOf("serverName"), "MyServer")
 
 // 这个 handler 会在 init() 中被添加到 ServerSocketChannel 的 pipeline
 .handler(new LoggingHandler(LogLevel.INFO))
 
 // 这些配置会被保存,在客户端连接时由 ServerBootstrapAcceptor 使用
 .childOption(ChannelOption.SO_KEEPALIVE, true)
 .childAttr(AttributeKey.valueOf("clientId"), "client")
 .childHandler(new ChannelInitializer<SocketChannel>() {
     @Override
     public void initChannel(SocketChannel ch) {
         ch.pipeline().addLast(new MyHandler());
     }
 });

这就是 Netty 中 ChannelInitializer 的完整工作原理!它解决了 channel 初始化时机的问题,是 Netty 启动流程中非常巧妙的设计。

IGBT模块封装中的银烧结技术:为什么特斯拉和比亚迪都在用这种黑科技? 本文深入解析了IGBT模块封装中的银烧结技术,揭示了其作为功率半导体封装工艺关键升级的原因。该技术通过低温烧结形成高熔点、高导热导电的银连接层,显著提升了模块的功率循环寿命、散热能力和高温工作稳定性,这正是特斯拉、比亚迪等行业巨头采用此项黑科技以释放电动汽车电驱系统极致性能的核心所在。 阅读详情

相关推荐

(25.08)Ubuntu20.04+ROS1复现FAST-LIO2

请确保在。

m0_69023437的博客 3994

netty理论之源码分析⑥ 细讲ChannelInitializer

1.ChannelInitializer是啥 一种特殊的ChannelInboundHandler,它提供了在通道注册到eventLoop后初始化通道的简单方法,ChannelInitializer的主要目的是为程序员提供了一个简单的工具,用于在某个Channel注册到EventLoop后,对这个Channel执行一些初始化操作。ChannelInitializer虽然会在一开始会被注册到Cha...

weixin_39666581的博客 3609

【客户案例】母婴行业头部品牌是如何做私域的

各品牌争相跑马圈地,想方设法圈住流量,建立品牌资产;私域运营是一项“重人力”的工作,在传统的品牌运营过程中,私域操盘手经常会由于一对多导致无法兼顾,只能通过提高触达次数的方式加大漏斗,这样难以让每个社群都发挥出应有的价值,甚至还会导致一定程度的用户流失。除了宝妈身份外激发的用户认同感、亲密度外,KOC们作为产品的使用者,自由选择的推品和自由创作的推广文案都更具有真实性、代表性,能够极大程度激发群友们的信任感,从而愿意为产品买单,转化复购水到渠成。不同阶段的宝妈,母婴知识的储存量和经验是不同的,K品牌还会。.

圈量SCRM系统-企微营销工具-私域流量运营软件 948

15-ChannelInitializer

文章目录ChannelInitializer一、继承关系二、源码2.1 注释2.2 源码分析2.3 handlerAdded和channelRegistered三、使用示例 ChannelInitializer ChannelInitializer 是一种特殊的 ChannelHandler,它也是一种 ChannelInboundHandler,它提供了在通道注册到 EventLoop 后初...

my_momo_csdn的博客 1959

DSP28335量产升级避坑指南:C2Prog串口烧录.hex文件,为什么我推荐COM1?

本文详细解析了DSP28335量产升级中C2Prog串口烧录.hex文件的最佳实践,重点推荐使用COM1端口以确保稳定性。通过实测数据和底层机制分析,揭示了Windows系统对COM1的特殊优化及C2Prog工具的时钟切换逻辑,帮助开发者规避常见陷阱,提升烧录成功率。

weixin_27066963的博客 384

【芯片验证随心记】1.SystemVerilog中,rand和randc的区别?如何用constraint实现randc?

在SystemVerilog里,randc 的“不重复循环”特性是用一个 周期性排列器(permutation engine) 实现的,而这个引擎在 LRM 里并没有公开。我们只能在 “用户空间” 用 rand + constraint 去模仿它的行为。每次随机化只取 queue.pop_front(),用完再洗。在4次随机化内,y会依次出现0,1,2,3各一次(顺序随机)每次随机化,x可能是0-3中的任意值,可能连续多次相同。每次随机化时,在未使用的值里随机挑一个;第5次随机化时,重新生成新的排列周期。

qq_43172512的博客 342

Netty源码篇 ChannelInitializer

netty 的 ChannelInitializer 与注意事项

qq_45090949的博客 2104

LightTools中VBA宏的编写入门

LightTools和VBA联动

bestgamer的博客 2348

Netty中ChannelInitializer的使用

Netty中ChannelInitializer的使用

Lemon_MY的博客 5592

Python爬虫实战:爬取小红书数据做爆款分析,我破解了签名加密+移动端反爬(附完整代码)

爬取小红书数据的核心,不是“简单的HTTP请求”,而是“理解移动端接口的加密逻辑和反爬规则”——从x-s/x-t签名破解到移动端UA伪装,再到行为模拟,每一步都是对移动端爬虫的深度理解。这套方案的价值在于,不仅能稳定抓取小红书数据,还能从数据中拆解出有价值的爆款特征,真正把“数据”变成“洞察”。对程序员来说,小红书爬虫不仅是技术练手,更是了解新媒体平台数据逻辑的窗口。希望这篇分享能帮到做新媒体分析或爬虫进阶的小伙伴,也欢迎在评论区交流小红书反爬和爆款分析的更多技巧!

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 2059

在Simulink中实现基于深度强化学习的控制算法仿真建模

通过上述步骤,你可以在Simulink中实现基于深度强化学习的控制算法仿真建模。这种方法适用于许多复杂的控制问题,尤其是当传统控制方法难以找到有效解决方案时。随着经验的积累,你可以进一步探索不同的深度强化学习算法及其变种,以适应更广泛的应用场景。此外,还可以结合其他先进技术(如迁移学习、多智能体协作等),提升模型的表现能力。

amy_mhd的博客 416

Netty源码解析之ChannelInitializer(三十六)

ChannelInitializer是一种特殊的ChannelInboundHandler,可以通过一种简单的方式(调用initChannel方法)来初始化Channel。 注意:当initChannel被执行完后,会将当前的handler从Pipeline中移除。 执行流程,点击 ServerBootstrap 类: 1、 2、点击AbstractBootstrap 类: // 服务器绑定端口监听 ChannelFuture f = b.bind(port).sync(); .

nandao158的博客 1334

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Netty 源码调试

自己学习笔记

weixin_44094842的博客 748

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

第五节 netty源码分析-ChannelPipeline的addLast方法解析

一、概述 在第四节中,分析了ServerBootstrap的bind()方法,主要分析了initAndRegister方法,这个方法调用的层次很深,还有几个主要的地方没有讲到,其中在initAndRegister()调用的ServerBootstrap.init()方法里面会用pipeline.addlast()方法。前面分析过new NioServerSocketChannel是默认创建DefaultChannelPipeline。所以就看io.netty.channel.DefaultChannelPi

Resee_Z的博客 3820

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

Netty启动流程源码解析:ServerBootstrap.init()如何决定Channel初始化

Netty作为高性能网络框架,其Channel与Pipeline机制是网络编程的核心基础。服务端启动时,从bind()到initAndRegister(),Channel的初始化由ServerBootstrap.init()完成。该方法将用户配置的ChannelOption、AttributeKey以及ChannelInitializer注入Pipeline,并通过ServerBootstrapAcceptor为每个新连接装配childHandler。理解init()的时机与设计,有助于排查连接创建但han

weixin_32642109的博客 175

Netty启动源码解析:ServerBootstrap.init()如何决定Pipeline生命周期

Netty作为Java网络编程领域的高性能NIO框架,其服务端启动流程中的Pipeline初始化与事件注册机制是理解连接管理的关键。在服务端Channel从创建到bind的链路中,ServerBootstrap.init()通过ChannelInitializer延迟注入业务Handler,并以eventLoop().execute()保证pipeline变更与EventLoop线程模型一致。掌握这一机制,有助于排查handler不生效、初始化顺序错乱等启动期问题,也能在设计高并发网关时更合理地规划连接生命

weixin_32288959的博客 212

Netty源码分析--认真系列(一)

Netty源码分析--认真系列(一)

java_rutu的博客 2056

Netty中AbstractChannelHandlerContext源码分析

AbstractChannelHandlerContext 是 ChannelHandlerContext 的抽象实现,位于 io.netty.channel 包中。它实现了 ChannelHandlerContext、ChannelInboundInvoker 和 ChannelOutboundInvoker 接口,提供事件传播、上下文访问和管道操作的核心功能。源码位置。

eclipseC的博客 1089

Netty学习之旅----源码分析netty服务端初始化流程(Reactor主从模式实现)

5.1.2 调用init()方法,具体实现在ServerBootstrap,主要完成如下三件事: 1)用相关选项配置Channel(NioSocketChannel) 2)将childHandler(ChannelInitializer子类handler)加入到管道,已便后续注册应用程序编排的处理链条(Handler)。 3)增加ServerBootstrapAcceptor,Handler处理器,主要是channelRead事件的处理,后续会重点讲解。 5.2 调用gourp().register()方法

m0_64867839的博客 199

[netty5: HttpObjectEncoder & HttpObjectDecoder]-源码解析

在阅读该篇文章之前,推荐先阅读以下内容: 类用于编码 HTTP 消息对象(如请求和响应),并根据不同的消息类型(如普通内容、分块内容或无内容)来处理编码过程。它支持对 HTTP 头、初始行、内容和尾部进行编码,并根据消息类型和内容长度动态调整内存分配,以提高编码效率。此外,还提供了一个方法来处理分块传输编码的内容,并在消息为空时输出合适的空缓冲区。 HttpRequestEncoder HttpRequestEncoder 类用于将 HTTP 请求消息(HttpRequest)编码为符合 HTTP 协议规范

... 1006

Netty学习之旅------源码分析ChannelPipeline实现原理,为什么大公司一定要使用微服务

1.2.1.1 ServerBootstrap init方法 1.2.1.2 group().register 方法 根据Netty线程模型,group()返回的是EventLoopGroup,然后Netty会从该EventLoopGroup中获取下一个EventLoop来执行。由于程序入口使用的是NioServerSocketChannel,故本例最终会使用NioEventLoop来作为事件处理器来服务,这里的register方法,其实现在NioEventLoo

m0_64867003的博客 191

Netty4源码分析——服务器启动

netty4线程模型 netty4服务器端的启动是由ServerBootstrap引导的,启动代码如下 public class TimeServer {     public void bind(int port) throws Exception {         EventLoopGroup bossGroup = new NioEventLoopGroup();

风居住的城市 1062

Netty4.0源码分析:客户端的启动过程

一、引言 开始学习Netty源码可以从它的启动过程入手。Netty客户端的启动需要构造一个io.netty.bootstrap.Bootstrap类,并可以通过它设置一系列参数。 我们从下面这个代码入手: public static void main(String[] args) throws InterruptedException { Bootstrap boot = new Bootst...

APlus 699

motan源码分析六:客户端与服务器的通信层分析

本章将分析motan的序列化和底层通信相关部分的代码。 1.在上一章中,有一个getrefers的操作,来获取所有服务器的引用,每个服务器的引用都是由DefaultRpcReferer来创建的 public DefaultRpcReferer(Class clz, URL url, URL serviceUrl) { super(clz, u

a1439226817的博客 1912

Netty源码分析之Bootstrap启动过程分析

Bootstrap 客户端部分 连接源码 NioSocketChannel 的初始化过程 ChannelFactory和Channel 类型的确定 Channel 实例化 关于unsafe字段的初始化 关于 pipeline 的初始化 关于 EventLoop 初始化 channel 的注册过程 handler 的添加过程 客户端连接分析 服务器端部分 Channel 的初始化过程 Channel

凌霄的专栏 1155

基于 Netty 的服务端开发:ServerBootstrap 启动到客户端接入的源码级解析

直接使用 JDK NIO 类库开发异步服务端,需要自行管理多路复用器 Selector、ServerSocketChannel、SocketChannel、ByteBuffer、SelectionKey 等底层组件,开发难度大且难以保证稳定性与高性能。Netty 在与用户交互的边界上做了良好的封装,`ServerBootstrap` 就是其面向 Socket 服务端的启动辅助类,用户通过它即可快速

gitblog_00004的博客 216
上一篇: Netty源码分析---Netty-Pipeline初始化流程详解
下一篇: Netty核心组件EventLoop详解
不早睡不改名@
博客等级 码龄5年 536粉丝 306原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值