Netty源码之初始化分析
Netty的使用比较格式化,结构比较固定。在了解源码的关键,是需要清楚各个属性值的意义及其初始化赋值过程。
初始化EventLoopGroup类
初始化的变量包括:
(children、parent、addTaskWakesUp、maxPendingTasks、executor、taskQueue、rejectedExecutionHandler、tailTasks、provider、selectStrategy、selector、unwrappedSelector)
执行链
事件循环组,通过具体的实现了NioEventLoopGroup创建。分为bossGroup(主组,主要负责连接事件,然后把连接后的交给workGroup处理)和workGroup(工作组,负责除连接外的其他事件,主要是读写事件)
1、NioEventLoopGroup
构造方法
public NioEventLoopGroup(int nThreads) {
this(nThreads, (Executor) null);
}
public NioEventLoopGroup(int nThreads, Executor executor) {
this(nThreads, executor, SelectorProvider.provider());
}
public NioEventLoopGroup(
int nThreads, Executor executor, final SelectorProvider selectorProvider) {
this(nThreads, executor, selectorProvider, DefaultSelectStrategyFactory.INSTANCE);
}
NioEventLoopGroup.png
传入的变量值,有nThreads(线程数量)、executor(执行器,此时为null)、selectorProvider(可以创建选择器selector)、selectStrategyFactory(策略工厂)
2、MultithreadEventLoopGroup
NioEventLoopGroup的父类MultithreadEventLoopGroup
MultithreadEventLoopGroup.png
如果传入线程数量不为null则是使用CPU核心数的2倍
2.1、拒绝策略是一个匿名内部类
RejectedExecutionException.png2.2、创建executor对象
MultithreadEventExecutorGroup.png1、创建ThreadPerTaskExecutor工厂,并对threadFactory赋值
ThreadPerTaskExecutor.png
2、对事件执行器数组children进行创建NioEventLoop对象(NIO事件循环对象)
EventExecutor.png
newChild.png
3、调用到顶层父类AbstractEventExecutor对parent赋值
AbstractEventExecutor.png
4、对任务队列taskQueue及rejectedExecutionHandler等的初始化
SingleThreadEventExecutor.png
其中最重要的是创建executor,返回一个可执行匿名内部类。当外部调用ThreadExecutorMap#execute方法会执行。
ThreadExecutorMap#apply.png
5、对尾任务队列赋值tailTasks
SingleThreadEventLoop.png
6、对provider、selectStrategy、selector、unwrappedSelector赋值,其中需要注意的是获取selectorTuple的值
NioEventLoop.png
在实例代码中创建了两个EventLoopGroup对象。所以,根据传入的参数可以确定类型是NioEventLoop的children数组的大小
ServerBootstrap服务启动辅助类
通过ServerBootstrap的group()、channel()及childHandler()方法对group(bossGroup)、childGroup(workGroup)、childHandler(自定义TestServerInitializer类)进行赋值
image.png
对NioServerSocketChannel类的构造方法constructor进行赋值
NioServerSocketChannel.png
bind方法
serverBootstrap.bind方法
bind.png
首先validate()方法验证group和channelFactory是否为空
bind.png
image.png
1、初始化并注册channel对象
initAndRegister.png1.1、创建NioServerSocketChannel对象
利用反射方法根据NioServerSocketChannel类的构造方法创建对象
newChannel.png
调用NioServerSocketChannel构造方法
NioServerSocketChannel.png
创建NioServerSocketChannel的实现了sun.nio.ch.ServerSocketChannelImpl
newSocket.png
1.2、NioServerSocketChannel类属性初始化赋值
首先调用父类方法,然后再对config赋值
NioServerSocketChannel.png
调用父类AbstractNioMessageChannel
AbstractNioMessageChannel.png
AbstractNioChannel类的父类调用
AbstractNioChannel.png
AbstractChannel类对parent、unsafe、pipeline赋值。这里都是NioServerSocketChannel属性值
AbstractChannel.png
其中,unsafe是生成NioMessageUnsafe类
NioMessageUnsafe.png
其中,pipeline生成DefaultChannelPipeline。并且pipline对象内部含有NioServerSocketChannel类,通过this传入,生成了head和tail节点的双向链表。head和tail中也包含pipline对象。所以Channel、pipline、链表节点可以相互获取
DefaultChannelPipeline.png
AbstractNioChannel对ch和readInterestOp属性值赋值,并把sun.nio.ch.ServerSocketChannelImpl[unbound]设置为非阻塞
AbstractNioChannel.png
2、对生成的NioServerSocketChannel类调用init方法
initAndRegister.png先对AbstractBootstra启动辅助类中是否含有Options和Attributes属性值进行处理,然后获取ChannelPipeline,并添加ChannelInitializer匿名实现类到ChannelPipeline链表中
init.png
2.1、匿名内部类ChannelInitializer的initChannel方法
ChannelInitializer.png2.2、ChannelPipeline调用addLast添加匿名内部类ChannelInitializer
io.netty.channel.DefaultChannelPipeline#addLast(io.netty.channel.ChannelHandler...)
此时ChannelHandler传入的是可变参数
addLast.png
addLast.png
2.3、addLast具体实现
io.netty.channel.DefaultChannelPipeline#addLast
addLast.png
1、checkMultiplicity方法检查注解并对added属性值赋值为true
对ChannelHandler.Sharable注解
checkMultiplicity.png
2、把添加的ChannelInitializer匿名类封装成AbstractChannelHandlerContext对象newCtx。
如果name值没有传,将会默认构建一个
image.png
3、对属性值name、pipeline、executor、executionMask、ordered及handler赋值。此时对象是通道处理器上下文AbstractChannelHandlerContext
传入的pipeline对象是把当前对象传进去的通过this传进去的
DefaultChannelHandlerContext.png
AbstractChannelHandlerContext.png
4、把封装后的对象添加到pipeline队列中
addLast0.png
5、把封装后的对象newCtx再次封装,并赋值给DefaultChannelPipeline的pendingHandlerCallbackHead属性
callHandlerCallbackLater.png
此时NioServerSocketChannel和pipeline的属性值
NioServerSocketChannel.png此时ServerBootstrap启动辅助类属性值
ServerBootstrap.png3、注册channel对象
register.png1、config对象
image.png
2、group对象
group.png
3、register方法
register.png
next.png
MultithreadEventExecutorGroup#next获取NioEventLoop对象
EventExecutor.png
3.1、SingleThreadEventLoop#register注册
io.netty.channel.SingleThreadEventLoop#register(io.netty.channel.Channel)
SingleThreadEventLoop.png
对channel、executor封装成DefaultChannelPromise对象
DefaultChannelPromise.png
注册ChannelPromise对象
io.netty.channel.SingleThreadEventLoop#register(io.netty.channel.ChannelPromise)
ChannelPromise.png
1、DefaultChannelPromise#channel对象
channel.png
2、unsafe对象
NioUnsafe.png
unsafe.png
3.1、AbstractUnsafe#register注册
AbstractUnsafe是AbstractChannel内部抽象类
io.netty.channel.AbstractChannel.AbstractUnsafe#register
获取eventLoop对象,并execute调用一个匿名内部类(假设这个匿名内部类是④)
AbstractUnsafe#register.png
3.2、SingleThreadEventExecutor#execute事件执行器调用执行匿名内部类
io.netty.util.concurrent.SingleThreadEventExecutor#execute(java.lang.Runnable)
wakesUpForTask方法返回true
execute.png
io.netty.util.concurrent.SingleThreadEventExecutor#execute(java.lang.Runnable, boolean)
execute.png
1、inEventLoop方法,判断当前执行线程与SingleThreadEventExecutor#thread属性值是否相同。
此时thread属性值是空,所以inEventLoop返回false
inEventLoop.png
SingleThreadEventExecutor#thread
thread.png
2、addTask方法,把当前匿名内部类④添加到任务队列SingleThreadEventExecutor#taskQueue中类型是Queue<Runnable>
addTask.png
offerTask.png
3、startThread开始执行线程
首先把state值,通过CAS操作由1(ST_NOT_STARTED)变为2(ST_STARTED)
startThread.png
4、SingleThreadEventExecutor#doStartThread
SingleThreadEventExecutor执行器类ThreadExecutorMap执行匿名内部类。所以在这里便可以调用到在2.2创建executor对象(假如这个匿名内部类是③)
doStartThread.png
io.netty.util.internal.ThreadExecutorMap#apply
这个方法返回的就是ThreadExecutorMap类,所以executor.execute(匿名内部类是③)便会调用到这里。传入的参数就是匿名内部类③。
apply.png
ThreadExecutorMap#apply方法
这里是在ThreadExecutorMap#apply方法调用过来的,所以command参数就是匿名内部类③。然后封装后的假设是匿名内部类②
apply.png
调用到ThreadPerTaskExecutor类的execute方法,这里包含的便是匿名内部类②
execute.png
在这个步骤过程中,需要考虑Runnable command封装的是那个匿名内部类。上面步骤是依次调用的。
所以,在threadFactory.newThread(command).start()调用start()方法便会依次执行匿名内部类②,匿名内部类是③
5、最终会调用回调到匿名内部类③的run方法
run.png
3.3、NioEventLoop#run事件循环启动
io.netty.channel.nio.NioEventLoop#run
run.png
io.netty.util.concurrent.SingleThreadEventExecutor#runAllTasks(long)
运行所有任务,从taskQueue获取(匿名内部类④也是放到这里的)
runAllTasks.png
io.netty.util.concurrent.AbstractEventExecutor#safeExecute
safeExecute.png
io.netty.channel.AbstractChannel.AbstractUnsafe#register
调用到匿名内部类④的register0方法
register.png
总结:
这边文章只是Netty所涉及的初始化,并没有涉及Netty的核心流程。
1、初始化EventLoopGroup事件循环组类和ServerBootstrap服务启动辅助类的初始化属性(直接赋值)
2、创建NioServerSocketChannel 服务端的处理类,这里面涉及pipeline的创建以及包含的链表
3、在pipeline添加ChannelInitializer节点所涉及的匿名内部类执行。
在匿名内部类添加任务有三种添加:
①、调用channel.eventLoop().execute方法时(nioEventLoopd.execute()),会添加到taskQueue任务队列
②、在调用pipeline.addLast()方法时,添加到pipeline的tail尾节点的前一个。并放置到pendingHandlerCallbackHead属性中
③、在调用executor.execute()方法时,先会调用ThreadExecutorMap类,最终会调用ThreadPerTaskExecutor#execute方法开启任务