Netty的深入浅出--40.serverBootstrap中channel方法和childHandler方法以及bind方法分析

本文深入剖析Netty服务器启动过程,从ServerBootstrap的channel方法入手,详细解读如何通过反射创建Channel实例,以及channelFactory和bind方法的工作原理。文章还探讨了自定义子处理器的设置与作用,以及ChannelFuture在启动过程中的角色。

在netty启动前,serverBootstrap基本上都要调用channel方法:

题外话:class文件是反射的起源,反射必定是通过class对象来实现的。

 进入channel方法:

无参构造:通过该方法传入的class对象,创建一个channel实例

 有参构造的话使用channelFactory:

 class对象传入到类ReflectiveChannelFactory中

通过调用默认的反射构造方法来创建channel对象

查看方法:只是将传进来的class对象赋值给了ReflectiveChannelFactory中的clazz变量

instantiate:实例化(动词)

 整体来说就是将ReflectiveChannelFactory(只是对class对象赋值给内部的clazz变量)这个对象传入到channelFactory方法中:

进入到channelFactory方法发现,它又调用了channelFactory方法 :

简单描述:问调用bind()的时候ChannelFactory工厂将会创建channel实例的

进一步跟进channelFactory这个方法中:

描述:不建议使用该方法,但是我们已经进入到这里了,那就分析它吧

 仔细一看发现还是在赋值:

现在我们简单来看一下传进来的这个NioServerSocketChannel方法

它跟nio中selectionChannel是一样,不断的等待连接 :

接下来就是我们自己定义 的子处理器:

我们看一下childHandler的源码:

设置channelHandler用于服务于channel的请求

到现在我们服务器的准备工作都完毕了

通过serverBootstrap的bind()方法来启动服务器:

创建一个新的channel以及通过端口号绑定它

进入跟进查看bind()方法:

validate():验证参数是否被设置好了

查看doBind()方法:

查看源码

题外话:一般以do开头命名的方法都是私有方法

我们先了解一下ChannelFuture:

它是一个接口,继承了Future

 而它又继承于并发包下的Future

对于这个Future 将会在后面用一个大章节进行详细说明:

对于channelFuture在下一章和Future一起 进行详细说明,我们回到之前:

分析initAndRegister

进入到initAndRegister中

这里channelFactory就是之前的传入class对象那个

 查看newChannel,发现跳转到一个接口上面:

很显然我们要找到真正的实现类

 

### Netty ServerBootstrap 中 NullPointerException 的原因分析 在 Java 编程中,`NullPointerException` 是一种常见的运行时异常。对于 `ServerBootstrap` 而言,这种异常通常发生在某些必要的配置未被正确设置的情况下。 #### 可能的原因及其解决方案 1. **未指定 Channel 类型** 如果在调用 `bind()` 方法之前没有通过 `channel(Class<? extends C> channelClass)` 设置具体的通道类,则会抛出 `NullPointerException`。这是因为 `AbstractBootstrap.channel(Class<? extends C> channelClass)` 方法会在参数为空时显式抛出此异常[^1]。 解决方案是在创建 `ServerBootstrap` 实例后立即调用 `.channel(NioServerSocketChannel.class)` 或其他合适的通道实现来指定服务器使用的具体通道类型。 2. **未正确设置 EventLoopGroup** 当调用 `group(EventLoopGroup parentGroup, EventLoopGroup childGroup)` 方法时,如果传入的 `parentGroup` 或 `childGroup` 参数为 `null`,则会触发 `NullPointerException`。这是因为在该方法内部有针对这些参数的非空校验逻辑[^2]。 正确的做法是确保传递给 `group(...)` 方法的两个 `EventLoopGroup` 对象均已被实例化且有效。例如: ```java EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); bootstrap.group(bossGroup, workerGroup); ``` 3. **缺少 ChildHandler 配置** 即使完成了上述两项基本配置,在绑定端口前如果没有定义如何处理客户端连接请求(即未调用 `.childHandler(ChannelInitializer<SocketChannel>)`),也可能间接导致后续操作失败而引发类似的错误行为[^3]。 应当提供一个自定义的 `ChannelInitializer` 来初始化新建立的每个子信道,并向其管道添加所需的处理器链。例如: ```java bootstrap.childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new ObjectEncoder()); pipeline.addLast(new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null))); pipeline.addLast(new RpcServerHandler(registerMap)); } }); ``` 4. **启动线程中的潜在问题** 在一些简单的例子中可能会看到像下面这样的代码片段用于启动服务端监听器[^4]: ```java public static void main(String[] args) { System.out.println("启动服务端开始"); new Thread(new ServerSocket()).start(); // 假设这里存在某种形式的服务端实现 System.out.println("启动服务端完成"); } ``` 这种方式虽然可以工作,但如果其中涉及到了复杂的异步流程或者依赖于外部资源加载等情况下的同步机制缺失的话也有可能造成意想不到的结果包括但不限于NPE等问题的发生。 综上所述,要彻底解决由 `ServerBootstrap` 引发的 `NullPointerException` 问题,需仔细检查以上提到的各项基础配置是否均已妥善安排到位。 ```java // 完整示例代码展示正确的配置过程 public class NettyServer { private final int port; public NettyServer(int port) { this.port = port; } public void run() throws InterruptedException { EventLoopGroup bossGroup = new NioEventLoopGroup(1); // 主线程组 EventLoopGroup workerGroup = new NioEventLoopGroup(); // 工作线程组 try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) // 指定使用 NIO 方式的 ServerSocketChannel .childHandler(new ChannelInitializer<SocketChannel>() { // 添加子信道初始化器 @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline p = ch.pipeline(); p.addLast(new StringEncoder()); // 示例编码器 p.addLast(new StringDecoder()); // 示例解码器 p.addLast(new SimpleChannelInboundHandler<String>() { // 处理业务逻辑 @Override protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception { System.out.println("收到消息:" + msg); ctx.writeAndFlush("已接收您的消息!"); } }); } }); // 绑定端口并等待关闭 ChannelFuture f = b.bind(port).sync(); f.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } } public static void main(String[] args) throws InterruptedException { new NettyServer(8080).run(); } } ``` ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值