netty

Netty源码之初始化分析

2020-04-18  本文已影响0人  loveFXX

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.png
2.2、创建executor对象
MultithreadEventExecutorGroup.png

1、创建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.png
1.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.png
2.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.png

3、注册channel对象

register.png

1、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方法开启任务

上一篇下一篇

猜你喜欢

热点阅读