美文网首页netty
Netty源码之初始化分析

Netty源码之初始化分析

作者: loveFXX | 来源:发表于2020-04-18 18:09 被阅读0次

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

    相关文章

      网友评论

        本文标题:Netty源码之初始化分析

        本文链接:https://www.haomeiwen.com/subject/njzvvhtx.html