<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          剖析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ī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日本欧美色 | 操比视频99 | 欧美日韩成人 | 青娱亚洲 | 国产不卡视 |