netty之源碼淺析

ChannelFactory 和 Channel 類型的確定

1.ReflectiveChannelFactory類保存了NioSocketChannel的class類,用於反射生成NioSocketChannel

2.channel(NioSocketChannel.class)返回了一個有channelFactory = new ReflectiveChannelFactory()的AbstractBootstrap對象

 

Channel 實例化

1. Channel實例化是在bind()的方法中完成的,根據bind()方法鏈路跟蹤,最後到達doResolveAndConnect方法,

private ChannelFuture doResolveAndConnect(final SocketAddress remoteAddress, final SocketAddress localAddress) {...}

這裏就是關鍵了。

    首先:final ChannelFuture regFuture = initAndRegister();  點進去可以看到channel = channelFactory.newChannel();  這裏的channelFactory是不是就是ReflectiveChannelFactory,然後通過反射生成NioSocketChannel,生成對象的同時會調NioSocketChannel的默認構造方法,找到NioSocketChannel的

private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();
public NioSocketChannel() {
    this(DEFAULT_SELECTOR_PROVIDER);
}

這個DEFAULT_SELECTOR_PROVIDER其實就是java中的NIO操作selector的一個provider(),接着會調用 newSocket 來打開一個新的 Java NIO SocketChannel,接着調用this繼續,可以發現parent爲null,跟蹤到最後面發現其實就是設置了ch,設置了readInterestOp爲讀事件,設置ch爲非阻塞而已,接着繼續調用super(),這裏會新建2個屬性unsafe(封裝了對 Java 底層 Socket 的操作)和pipeline,所以這樣看來每個channel是會對應一個自己的unsafe和pipeline,這樣一個初始化的channel就生成了,還是略微有點複雜。

   這裏有兩個初始化關注一下:

   unsafe:我們發現newUnsafe()其實是個抽象方法,那麼AbstractChannel的子類中肯定實現了這個方法,然後我們知道生成的類型是NioSocketChannel,找到該方法,發現調用new NioSocketChannelUnsafe(),其實是一個 NioSocketChannelUnsafe 的實例。

   pipeline:這裏簡單來說就是pipleline中保存了channel和tail,head的屬性,tail和head是雙向鏈表的形式。

   根據類的關係圖可知tail是Inbound,而head是outbound。

   然後:剛纔其實才僅僅看了channelFactory.newChannel()實例化過程,接下來就該初始化了,調用init(),然後有這行代碼p.addLast(config.handler()); 最終發現config.handler()實際取的就是AbstractBootStrap中的ChannelHandler handler屬性並且這個屬性是在客戶端調用handler(...)方法設值的,類型爲ChannelInitializer 實例,因此這時候pipleline的結果爲

head-> ChannelInitializer->tail。

我們在對addLaset()方法進行分析,如果handler不是重名的情況下,會創建一個AbstractChannelHandlerContext,其實就是把handler封裝成了DefaultChannelHandlerContext對象,這裏有兩個Inbound和outbound屬性的判斷,根據類圖可以知道ChannelInitializer實現了Inbound,所有Inbound=true,outbound=false,最後調用addLast0插入到tail之前。

   最後:這樣實例化和初始化channel2個步驟完成了,接下來就是註冊的過程了,註冊過程比較簡單,就是把clannel註冊到nioEventLoop的selector上,當然這裏要先涉及到nioEventLoop的初始化操作(這步操作比較簡單,系統會根據設置的線程數量去初始化線程池大小,如果沒有設置就取cpu數*2),一個nioEventLoop是綁定了一個selector,而源碼中的next()實際就是獲取一個當前可用的nioEventLoop對象。

 

自定義channel添加過程

  自定義channel在AbstractChannel的register0中完成添加,也就是說在channel實例化和初始化後就會添加自定義的channel,pipeline.fireChannelRegistered();這行代碼進行跟蹤,會發現根據findContextInbound()會找到ChannelInitializer,然後調用ChannelInitializer的channelRegistered,關鍵來了,channelRegistered的方法又會調用initChannel,而這個方法是抽象方法,由我們自定義的channel實現,所以這裏就加入了自定義channel,最後ChannelInitializer會remove自己,所以此時就變成了head-> myHandler->tail,此時自定義添加channel高一段落。

 

客戶端連接過程在channel實例,初始化和註冊和添加完成後,接下來就是真正的connect了)

  分析BootStrap的doResolveAndConnect0方法,最後會調用channel.connect,此時的channel其實是NioSocketChannel,然後會進入AbstractChannelHandlerContext的connect,看這行代碼final AbstractChannelHandlerContext next = findContextOutbound(); ,無非就是找到第一個outbound爲true的ChannelHandler,這列可以知道第一個就是HeadContext,然後最後就是unsafe.connect(remoteAddress, localAddress, promise); 這個一看就知道是調用底層java的AbstractNioUnsafe的connect,根據doConnect進入NioSocketChannel的doConnect找到真正的方法boolean connected = SocketUtils.connect(javaChannel(), remoteAddress); 到此爲止客戶端的connect纔算完成。

 

服務端Channel實例化

  大概的流程跟客戶端一致,只是事件變成了SelectionKey.OP_ACCEPT,還有值得注意的就是原本newUnsafe()應該返回AbstractChannel的newUnsafe,然而AbstractNioMessageChannel又繼承了AbstractChannel,所以最終調用的是AbstractNioMessageChannel的newUnsafe(),返回NioMessageUnsafe實例。

 

bossGroup和workerGroup

   這裏的bossGroup主要處理accept連接,當收到accept事件後,會調用ServerBootstrapAcceptor的channelRead方法,然後就會找到workerGroup的某個eventLoop和新接入進來NioSocketChannel關聯,之後就用workerGroup中的某個線程處理相應的io事件。

    要關注的是,bossGroup初始化時,即調用init(channel);會向NioServerSocketChannel的pipline添加ChannelInitializer,之後調用config().group().register(channel);就把NioServerSocketChannel註冊到了bossGroup的一個線程中,註冊成功後又會執行pipeline.fireChannelRegistered();這個關鍵代碼,找到第一個outbound爲true的channelContext,即ChannelInitializer並調用channelRegistered(),所以此時pipline就變成了head->LoggerHandler->ServerBootstrapAcceptor->tail。

    而wokerGroup則是通過ServerBootstrapAcceptor中channelRead和接入進來的NioSocketChannel關聯起來的,handler的添加基本相同,這裏就不做過多解釋了。

 

  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章