<p id="m2nkj"><option id="m2nkj"><big id="m2nkj"></big></option></p>
    <strong id="m2nkj"></strong>
    <ruby id="m2nkj"></ruby>

    <var id="m2nkj"></var>
  • 剖析Netty之底層原理(二)

    共 1663字,需瀏覽 4分鐘

     ·

    2020-11-17 23:23

    逃離整個宇宙碰撞的意外

    穿過黑暗盡頭又通往哪里

    時間也被吞沒到了無人之際

    是否能留住和你的記憶

    星空不規(guī)則

    無盡下墜


    上次說到調(diào)用

    io.netty.bootstrap.AbstractBootstrap#init

    方法

    由于是服務(wù)端,則實(shí)際調(diào)用

    io.netty.bootstrap.ServerBootstrap#init

    方法


    b26dc35340e1386a1109a7e5743debfe.webp


    132-133行:設(shè)置通道相關(guān)屬性

    135行:從通道中獲取

    io.netty.channel.ChannelPipeline

    獲取的ChannelPipeline是獲取的啥呢?

    這里是從一個

    io.netty.channel.Channel

    中獲取的,這個Channel,是前面

    0041c5f49a26afee1bdb73683d777f80.webp

    中得到的,上文說到,這里是通過反射調(diào)用對應(yīng)類的構(gòu)造方法獲取的,而這個對應(yīng)類,是傳入的

    io.netty.channel.socket.nio.NioServerSocketChannel

    那么這里的

    io.netty.channel.Channel#pipeline


    0c43823eebd76d45062a251ee0b76cfd.webp

    實(shí)質(zhì)是調(diào)用上圖顯示的

    io.netty.channel.AbstractChannel#pipeline

    方法,因?yàn)?/span>

    io.netty.channel.socket.nio.NioServerSocketChannel

    是繼承于

    io.netty.channel.AbstractChannel


    a37fa124dc55f0cbde8ed87352885e64.webp


    這里是直接返回AbstractChannel的一個屬性值

    io.netty.channel.DefaultChannelPipeline

    那么這個屬性值是什么時候賦值的呢?

    剖析Netty之底層原理(一)中,有說到過,初始化的Channel時,是通過反射調(diào)用

    io.netty.channel.socket.nio.NioServerSocketChannel

    的無參構(gòu)造,

    這里再回顧下這個無參構(gòu)造:

    b49b91647c186140662b48dc1500fea9.webp


    執(zhí)行完

    io.netty.channel.socket.nio.NioServerSocketChannel#newSocket

    之后,得到一個

    java.nio.channels.ServerSocketChannel對象,再調(diào)用

    io.netty.channel.socket.nio.NioServerSocketChannel#NioServerSocketChannel(java.nio.channels.ServerSocketChannel)

    方法

    即:


    a1e490fddb126f4a243edc43393ee111.webp

    這里調(diào)用了父類方法,我們逐個點(diǎn)擊進(jìn)去

    0ec84ad9ab7d49d80e5966640ccfaf0f.webp

    777117060e29f7881b446fc30863a24b.webp


    85ee555e48d4aa1d0d5d8d6372eeb950.webp


    如上述過程所示,這里調(diào)用了

    io.netty.channel.AbstractChannel#AbstractChannel(io.netty.channel.Channel)

    方法

    設(shè)置了屬性值

    io.netty.channel.DefaultChannelPipeline

    d88a932c8d83ac1c717f7ff381c7a91f.webp

    這里的

    newChannelPipeline

    方法,實(shí)質(zhì)調(diào)用

    io.netty.channel.AbstractChannel#newChannelPipeline

    方法,


    cd2b38e363cd13713dad6170b02a742f.webp


    dafaa9df6a0fcad1f9dfcf026c3e7e50.webp



    這里我們需要重點(diǎn)看這個類:

    io.netty.channel.AbstractChannelHandlerContext

    上圖可以發(fā)現(xiàn),設(shè)置了

    io.netty.channel.AbstractChannelHandlerContext#next


    io.netty.channel.AbstractChannelHandlerContext#prev

    這里維護(hù)的兩個

    io.netty.channel.AbstractChannelHandlerContext

    其結(jié)果構(gòu)成一個雙向鏈表

    類似這樣子的一個結(jié)果:

    006bdb63519e452435a344baee9c80c9.webp


    關(guān)于這個設(shè)計的目的,待后續(xù)使用到的時候再進(jìn)一步了解,這里先了解到此


    接著說上面的初始化方法

    137-138行:將類屬性值,賦予成員變量,這里需要指出的是,這里的

    EventLoopGroup是前面我們設(shè)置的工作線程組,

    ChannelHandler是前面我們設(shè)置的childHandler

    即:


    5c2321a9cfffa3a873292422848571e2.webp



    140-143行:將Map, Object>

    轉(zhuǎn)化為Entry, Object>[]數(shù)組

    這里的Map,?Object>,是在初始化ServerbootStrap中設(shè)置的

    0abea5cce764d44d962f3cfe663c1997.webp

    即,設(shè)置的.option


    e654ab3f50d7ad26094b76d3e45136b1.webp

    ?

    145-162行:主要是設(shè)置這個ChannelPipeline

    調(diào)用

    io.netty.channel.ChannelPipeline#addLast(io.netty.channel.ChannelHandler...)

    方法

    傳入

    io.netty.channel.ChannelInitializer

    對象,這里重寫了

    io.netty.channel.ChannelInitializer#initChannel(io.netty.channel.ChannelHandlerContext)

    方法,

    將自定義的Handler設(shè)置到pipeline中

    這里先不深入到Pipeline中描述如何添加自定義的Handler了,后續(xù)將有詳細(xì)的說明


    這里我們需要重點(diǎn)看下這幾個addLast方法:截圖顯示下


    f503e4c4ee2dfa62ec73395cede50e52.webp

    這里主要分為2個部分,一個是148行-152行,另一部分是154-160行

    148-152行:

    這里重寫了

    io.netty.channel.ChannelInitializer#initChannel

    方法,傳入的這個通道,很明顯就是前面設(shè)置的

    io.netty.channel.socket.nio.NioServerSocketChannel

    從服務(wù)端socket通道中獲取到pipeline

    149行,讀取配置的handler,前面并沒有設(shè)置,所以這里是null

    故而不會執(zhí)行if方法,結(jié)束運(yùn)行

    154-160行:

    154行,從

    io.netty.channel.socket.nio.NioServerSocketChannel

    獲取事件輪詢同時執(zhí)行一個線程方法

    先看這個

    java.util.concurrent.Executor#execute

    方法實(shí)際執(zhí)行

    io.netty.util.concurrent.SingleThreadEventExecutor#execute(java.lang.Runnable)


    df90ee702415f60137a4f6ea1093795e.webp


    接著執(zhí)行

    io.netty.util.concurrent.SingleThreadEventExecutor#execute(java.lang.Runnable, boolean)


    f68ee787a9b15a119a67da92d8f20d52.webp


    如上圖所示,這里簡單描述下這段代碼,

    首先添加前面的addLast方法添加到任務(wù),然后判斷當(dāng)前事件是否輪詢,如果沒有輪詢,則執(zhí)行if方法體的方法

    這里有個

    io.netty.util.concurrent.SingleThreadEventExecutor#startThread

    方法,

    跟蹤進(jìn)去


    2eb21ff460d8c1b194fd79005452ee51.webp


    注意看947行,有個?

    io.netty.util.concurrent.SingleThreadEventExecutor#doStartThread

    方法,

    跟蹤進(jìn)去

    3cc9f066b7ee9bd712be05f4d59bb97e.webp


    這里會通過線程操作執(zhí)行run方法<上圖989行代碼>

    然后這個this在這里指代的是什么呢?然后執(zhí)行的run方法又是什么方法呢?

    前面的分析不難看出,設(shè)置的事件輪詢線程組是

    io.netty.channel.nio.NioEventLoopGroup

    所以這里可以猜到,執(zhí)行的應(yīng)該是

    io.netty.channel.nio.NioEventLoop#run

    方法

    看下這幾者之間的類關(guān)系圖


    a16e9b7af9856d1d8465dee2060cbdba.webp


    關(guān)于幾者初始化關(guān)系,會在后面用圖表示出來,這里先不在詳述

    所以這里執(zhí)行的是

    io.netty.channel.nio.NioEventLoop#run

    即:


    763c944c388732afdd544ca938e48f88.webp


    這里的一大段代碼,后面會詳細(xì)說到,目前僅僅做一個簡單的介紹,此邏輯類似NIO中,通過輪詢多路復(fù)用器中每個通道的不同狀態(tài),然后做不同的事,此邏輯類似的,根據(jù)不同的情況,完成不一樣的邏輯《處理輪詢key,以及數(shù)據(jù)讀寫等等操作》,這里的for循環(huán),是個死循環(huán),即程序運(yùn)行期間則一直監(jiān)聽。


    至此,初始化方法

    io.netty.bootstrap.ServerBootstrap#init

    結(jié)束


    回到

    io.netty.bootstrap.AbstractBootstrap#initAndRegister

    繼續(xù)

    怕忘記了,這里截圖顯示下:


    ac95a7a8a5fc16bbcb6bd25ed93417e5.webp


    第311行結(jié)束

    異常情況先不談

    看第323行:

    c4726f99d14e71134f6ca3c426134cf2.webp

    這里調(diào)用了一個config方法,然后調(diào)用group方法,在調(diào)用register方法,將前面的Channel注冊進(jìn)去,這里挨個詳述源碼:


    config方法


    b27f59081dc2d396946811ed708bdf9c.webp

    由于這里是服務(wù)端,則調(diào)用

    io.netty.bootstrap.ServerBootstrap#config

    方法


    c9e2a69e1d1fa01f916ec2ad1e913ca5.webp

    這里直接返回一個config


    f01c81090529e1a9b76e3ad0285599bf.webp


    簡單看下這個

    io.netty.bootstrap.ServerBootstrapConfig


    c02fc81011f349fd326c783979d83c6d.webp

    這里是其簡單的類關(guān)系圖,這里new一個ServerBootstrapConfig的時候傳入了一個this,簡單看下,this到底做了什么?

    追蹤到底,這里是給父類

    io.netty.bootstrap.AbstractBootstrapConfig

    的bootstrap賦值


    5cdb34919f74ef924b3e9e79739a5be5.webp



    group方法

    這里能理解到了,這個group方法,則是調(diào)用

    io.netty.bootstrap.AbstractBootstrapConfig#group

    方法


    cd2d8cd3773d1bda7f417a0bcb40c6fb.webp

    返回調(diào)用的是bootstrap.group()方法,這里即調(diào)用

    ServerBootstrapConfig的group方法,然而,在

    ServerBootstrapConfig類中,并沒有找到對應(yīng)方法,于是想當(dāng)然的可以去父類中找

    于是在其父類中找到

    io.netty.bootstrap.AbstractBootstrap#group()

    ec958ec7573b26997f8797691ddd7963.webp


    這里是直接返回的一個group,


    cb00f11253339e4d0d46f28d8842c08a.webp

    這個

    io.netty.channel.EventLoopGroup

    則是前面設(shè)置的一個

    io.netty.channel.nio.NioEventLoopGroup

    即bossGroup


    35a2b9ef7a84db34e9d8c035feba13a6.webp

    因?yàn)樵谇懊嬖创a中,這個EventLoopGroup,才被賦值到

    io.netty.bootstrap.AbstractBootstrapgroup屬性


    最后調(diào)用register方法,則實(shí)質(zhì)調(diào)用的

    io.netty.channel.nio.NioEventLoopGroupregister方法

    然后在NioEventLoopGroup中并沒有找到這個方法,則去父類中找

    最后發(fā)現(xiàn)是其父類

    io.netty.channel.MultithreadEventLoopGroup#register(io.netty.channel.Channel)

    中找到方法


    33d38dcd9dc0f4d8f664fce195d05551.webp


    首先這里調(diào)用next()方法,這個next()方法其實(shí)是調(diào)用父類的next()方法


    io.netty.util.concurrent.MultithreadEventExecutorGroup#next


    ff894dcc0de4d2d81177ec5040d4dd0a.webp

    如上圖所示,這里的chooser,是初始化階段提到過的chooser,即2種初始化線程數(shù)量的方法,然后這里可能根據(jù)自身電腦配置不一樣會有不一樣的

    io.netty.util.concurrent.EventExecutorChooserFactory.EventExecutorChooser

    實(shí)例

    這里可以發(fā)現(xiàn)next方法主要是調(diào)用下一個線程實(shí)例

    結(jié)合注冊方法,這里主要將當(dāng)前的這個

    io.netty.channel.Channel

    注冊到下一個線程池里線程實(shí)例中

    這里先簡單了解下,注冊到線程實(shí)例的方法,調(diào)用的是

    io.netty.channel.SingleThreadEventLoop#register(io.netty.channel.ChannelPromise)

    方法,即單線程事件輪詢器的注冊方法


    注冊完成后,返回一個

    io.netty.channel.ChannelFuture

    實(shí)例

    到此,初始注冊方法就先告一段落


    回到前面說到的方法:


    cd7e81bfd625df3646cf28b3eeda7c91.webp

    前面簡單簡述了紅色標(biāo)記的方法,總結(jié)起來就是構(gòu)建pipeline,初始化相關(guān)參數(shù)信息

    下面上圖接著273行:

    獲取到前面的channel

    下面的其他方法和if判斷邏輯先略過,這里我們主要看281行和299行的doBind0方法

    io.netty.bootstrap.AbstractBootstrap#doBind0

    方法


    68e8e739bc8b49eecc4e9a43700e24b2.webp


    如上圖所示,這里是直接將輪詢通道中綁定的事件,執(zhí)行線程方法

    重點(diǎn)看356行:

    af34b9ec7652ceeafc950bbb046cfa5b.webp


    調(diào)用

    io.netty.channel.AbstractChannel#bind(java.net.SocketAddress, io.netty.channel.ChannelPromise)

    方法


    a356872ec86e2e701524b611e8aed7b5.webp


    繼續(xù)調(diào)用

    io.netty.channel.DefaultChannelPipeline#bind(java.net.SocketAddress, io.netty.channel.ChannelPromise)

    方法


    9f8241eb45420772c13464925e6cc5a5.webp


    繼續(xù)調(diào)用

    io.netty.channel.AbstractChannelHandlerContext#bind(java.net.SocketAddress, io.netty.channel.ChannelPromise)

    方法

    778b3112168e10ca9a3d2178756bcb61.webp


    這里通過層層調(diào)用,完成對端口的監(jiān)聽和其他

    io.netty.channel.ChannelPromise

    的操作


    到此結(jié)束分享代碼追蹤層面的Netty服務(wù)端的運(yùn)行邏輯,即什么時候輪詢,什么時候執(zhí)行響應(yīng)Task。有一些亂,可以根據(jù)看源碼挨個挨個來,后面會整理下思路和層級邏輯,畫出類的時序圖來幫助理解和消化,本期就先到這兒了,頭有點(diǎn)大.......



    初學(xué),請多指教,歡迎關(guān)注轉(zhuǎn)發(fā).......


    有喜歡的歡迎轉(zhuǎn)發(fā),點(diǎn)擊下面圖片關(guān)注公眾號,不定期更新干貨!


    瀏覽 33
    點(diǎn)贊
    評論
    收藏
    分享

    手機(jī)掃一掃分享

    分享
    舉報
    評論
    圖片
    表情
    推薦
    點(diǎn)贊
    評論
    收藏
    分享

    手機(jī)掃一掃分享

    分享
    舉報
    <p id="m2nkj"><option id="m2nkj"><big id="m2nkj"></big></option></p>
    <strong id="m2nkj"></strong>
    <ruby id="m2nkj"></ruby>

    <var id="m2nkj"></var>
  • 美女操逼应用 | 成人亚洲网 | 国产美女在线观看 | 成人一级大片 | av天天av无码av天天爽 Chinese国产人妖TS | 高清在线免费观看亚洲视频 | 六月色婷 | 国产精品久久久成人 | 一级片在线免费看 | 免费一级毛片毛多水多 |