Netty源码深度解析

本文主要解析Netty源码,Netty是对Java原生NIO的封装,使用更方便。详细介绍了Netty服务端创建过程,包括NioEventLoopGroup、ServerBootstrap等类的使用。还阐述了Netty运行模式,基于Reactor主从架构,利用零拷贝技术提升性能,号称支持百万连接。

今天,聊一聊Netty源码。Netty在我们Java圈中挺出名的,因为其高性能,号称支持百万的客户端连接,因此,很多框架通讯都是采用了Netty,如Dubbo、Zookeeper、Spring WebFlux等等。简单来说,Netty实际上是对Java原生NIO的封装,因为Java提供的原生NIO用起来确实不太方便,因此Netty做了封装,使得我们在使用Netty的时候,写一些模板性的代码即可,并且只需要添加一个或多个我们自己写好的ChannelHandler类,在对应的方法中,写好业务逻辑即可,而不必关注NIO使用上的一些细节。先看看我写的,以Netty服务端为例,如下图所示:
在这里插入图片描述
这是一个最简单的Netty Server,并且只有NettyServerHandler是我写的,它继承自SimpleChannelInboundHandler抽象类,如下图所示:
在这里插入图片描述
回到NettyServer类中,先看NioEventLoopGroup,这是Netty提供的类,可以把它理解为是线程池,当然和我们常用的线程池还是有很大的不同的,创建NioEventLoopGroup,该类提供了有参构造和无参构造,如果是有参的话,传入一个具体的数值,就是指明创建多少个NioEventLoop,如果是无参构造的话,默认是创建CPU核心数×2,这块将在代码中体现,如下图所示:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
以上就是NioEventLoopGroup构造方法的调用链路,其中,在它的父类MultithreadEventLoopGroup中,就会判断传入的nThreads是否为空,为空则是CPU核心数×2,不为空则以传入的nThreads为准,如下图所示:
在这里插入图片描述
在该构造方法中,先是判断传入的executor是否为空,为空则初始化一个ThreadPerTaskExecutor对象并赋值给executor,看看ThreadPerTaskExecutor,如下图所示:
在这里插入图片描述
由此可以看到,调用ThreadPerTaskExecutor#execute()方法,传入一个Runnable对象,它就会把我们传入的Runnable对象做一下包装(实际上就是创建一个Thread对象,把Runnable对象作为入参传入),并调用start方法,启动线程。回到MultithreadEventExecutorGroup的有参构造中,继续往下看,然后就是初始化他的成员属性children,它是一个EventExecutor类型的数组,接着就是根据我们传入的线程数做循环,在循环中调用MultithreadEventExecutorGroup#newChild()方法,给数组中的每一个元素赋值,看看该方法,如下图所示:
在这里插入图片描述
在这里插入图片描述
创建的是NioEventLoop,调用的是有参构造,传入了NioEventLoopGroup对象、ThreadPerTaskExecutor对象、SelectorProvider对象、DefaultSelectStrategyFactory对象、RejectedExecutionHandler对象、EventLoopTaskQueueFactory对象、EventLoopTaskQueueFactory对象。进到构造方法中看看,如下图所示:
在这里插入图片描述
构造中调用了父类的构造,最好也点进去看看,可能会有一些初始化的逻辑,如下图所示:
在这里插入图片描述
在这里插入图片描述
上图中的父类构造中,初始化了一个taskQueue成员属性,这是一个阻塞队列,通常用来做异步操作的,挺重要的,先记下来,后续很可能会用到,继续看父类的构造,如下图所示:
在这里插入图片描述
在这里插入图片描述
到上图就没什么可看的了,就是把NioEventLoopGroup做了一下赋值而已。到这里,NioEventLoopGroup的构造方法,及其父类的构造方法全部看完了,回到NettyServer类中:如下图所示:
在这里插入图片描述
接着就是创建ServerBootstrap对象,并且通过链式调用,给ServerBootstrap属性赋值,包括调用ServerBootstrap#group()方法,将上面创建的两个NioEventLoopGroup对象传入,可以点进去看看,如下图所示:
在这里插入图片描述
再看看父类的group()方法:
在这里插入图片描述
这里就可以记录一下:我们创建了两个NioEventLoopGroup对象,分别是 bossGroup 和 workerGroup,分别给ServerBootstrap的group属性和childGroup属性进行了赋值。再看看ServerBootstrap#channel()方法,传入的是NioServerSocketChannel.class,如下图所示:
在这里插入图片描述
再看看,最终就是给ServerBootstrap的channelFactory属性赋值,赋值的对象是ReflectiveChannelFactory,创建该对象的时候调用的是有参构造,传入的就是NioServerSocketChannel.class,这个有参构造就不看了,后续还会使用到ReflectiveChannelFactory。再看看ServerBootstrap#childHandler()方法,传入ChannelInitializer的实现类,如下图所示:
在这里插入图片描述
就是把传入的ChannelInitializer的实现类赋值给childHandler属性。以上就是ServerBootstrap类创建后的赋值,再来看ServerBootstrap#bind()方法,这个方法很重要,涉及到了Netty怎么启动注册并且绑定端口,点进去看看,如下图所示:
在这里插入图片描述
最终调用到了ServerBootstrap#doBind()方法,在该方法中发有一个ServerBootstrap#initAndRegister()方法,一般方法中带有"init"、"start"等单词的需要重点关注下,点到该方法中看看它干了些啥,如下图所示:
在这里插入图片描述
发现用到了ServerBootstrap的channelFactory属性,这个属性不就是前面我说的ReflectiveChannelFactory类的对象吗,那就看看ReflectiveChannelFactory#newChannel()方法,如下图所示:
在这里插入图片描述
会发现就干了一件事,通过反射创建了某个对象,而这个constructor其实就是之前传入的NioServerSocketChannel.class的默认构造,因此创建的也是NioServerSocketChannel对象,可以看看NioServerSocketChannel类的构造方法,看看构造方法中有没有做一些初始化,或者赋值之类的,如下图所示:
在这里插入图片描述
在上图中,比较核心的就是NioServerSocketChannel#newChannel()方法,通过这个方法可以得到一个ServerSocketChannel对象,而这个对象实际上就是JDK提供的类。如果我们不用Netty,直接用JDK提供的原生类开发NIO,就必然会用到这个类,所以说,Netty本质上就是用JDK原生的NIO做了封装,使之用起来更简单方便。在最后的有参构造中就接收了ServerSocketChannel对象,并且构造方法中调用了父类的构造,传入了该对象和SelectionKey.OP_ACCEPT,第二个参数,看过JDK原生代码的应该知道,这表示,服务端接收的是客户端的连接请求,除了SelectionKey.OP_ACCEPT之外,还有下图中的几个:
在这里插入图片描述
分别表示不同的ServerSocketChanne/SocketChannel上发生的不同事件类型。另外一个就是创建的是NioServerSocketChannelConfig对象,并给属性config赋值,调用的是它的有参构造,传了两个参数:一个是NioServerSocketChannel它自己,另一个是ServerSocketChannel对象,就是之前通过NioServerSocketChann

评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值