摘要:本篇將通過實(shí)例化過程,來深入剖析。及初始化完成后,它們會(huì)相互連接。我們?cè)诨氐降臉?gòu)造方法父類構(gòu)造方法調(diào)用完成后,還要初始化一下自己的配置對(duì)象是的內(nèi)部類而又是繼承自,通過代碼分析,此對(duì)象就是就會(huì)對(duì)底層一些配置設(shè)置行為的封裝。
根據(jù)上一篇《Netty4.x 源碼實(shí)戰(zhàn)系列(二):服務(wù)端bind流程詳解》所述,在進(jìn)行服務(wù)端開發(fā)時(shí),必須通過ServerBootstrap引導(dǎo)類的channel方法來指定channel類型, channel方法的調(diào)用其實(shí)就是實(shí)例化了一個(gè)用于生成此channel類型對(duì)象的工廠對(duì)象。 并且在bind調(diào)用后,會(huì)調(diào)用此工廠對(duì)象來生成一個(gè)新channel。
本篇將通過NioServerSocketChannel實(shí)例化過程,來深入剖析NioServerSocketChannel。
在開始代碼分析之前,我們先看一下NioServerSocketChannel的類繼承結(jié)構(gòu)圖:
在綁定偵聽端口過程中,我們調(diào)用了AbstractBootstrap的initAndRegister方法來完成channel的創(chuàng)建與初始化,channel實(shí)例化代碼如下:
channelFactory.newChannel()
而channelFactory對(duì)象是我們通過ServerBootstrap.channel方法的調(diào)用生成的
public B channel(Class extends C> channelClass) { if (channelClass == null) { throw new NullPointerException("channelClass"); } return channelFactory(new ReflectiveChannelFactory(channelClass)); }
通過代碼可知,此工廠對(duì)象是ReflectiveChannelFactory實(shí)例
public class ReflectiveChannelFactoryimplements ChannelFactory { private final Class extends T> clazz; public ReflectiveChannelFactory(Class extends T> clazz) { if (clazz == null) { throw new NullPointerException("clazz"); } this.clazz = clazz; } @Override public T newChannel() { try { return clazz.getConstructor().newInstance(); } catch (Throwable t) { throw new ChannelException("Unable to create Channel from class " + clazz, t); } } }
所以 channelFactory.newChannel() 實(shí)例化其實(shí)就是NioServerSocketChannel無參構(gòu)造方法反射而成。
NioServerSocketChannel實(shí)例化過程分析我們先看一下NioServerSocketChannel的無參構(gòu)造代碼
public NioServerSocketChannel() { this(newSocket(DEFAULT_SELECTOR_PROVIDER)); }
無參構(gòu)造方法中有兩個(gè)關(guān)鍵點(diǎn):
1、使用默認(rèn)的多路復(fù)用器輔助類 DEFAULT_SELECTOR_PROVIDER
private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();
2、通過newSocket創(chuàng)建ServerSocketChannel
private static ServerSocketChannel newSocket(SelectorProvider provider) { try { return provider.openServerSocketChannel(); } catch (IOException e) { throw new ChannelException( "Failed to open a server socket.", e); } }
我們將newSocket生成的ServerSocketChannel對(duì)象繼續(xù)傳遞給本類中的NioServerSocketChannel(ServerSocketChannel channel)構(gòu)造方法
public NioServerSocketChannel(ServerSocketChannel channel) { super(null, channel, SelectionKey.OP_ACCEPT); config = new NioServerSocketChannelConfig(this, javaChannel().socket()); }
在其內(nèi)部,我們會(huì)調(diào)用父類AbstractNioMessageChannel的構(gòu)造方法:
protected AbstractNioMessageChannel(Channel parent, SelectableChannel ch, int readInterestOp) { super(parent, ch, readInterestOp); }
因?yàn)槭欠?wù)端新生成的channel,第一個(gè)參數(shù)指定為null,表示沒有父channel,第二個(gè)參數(shù)指定為ServerSocketChannel,第三個(gè)參數(shù)指定ServerSocketChannel關(guān)心的事件類型為SelectionKey.OP_ACCEPT。
在AbstractNioMessageChannel內(nèi)部會(huì)繼續(xù)調(diào)用父類AbstractNioChannel的構(gòu)造方法:
protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) { // 繼續(xù)調(diào)用父類構(gòu)造方法 super(parent); // 將ServerSocketChannel對(duì)象保存 this.ch = ch; // 設(shè)置關(guān)心的事件 this.readInterestOp = readInterestOp; try { // 設(shè)置當(dāng)前通道為非阻塞的 ch.configureBlocking(false); } catch (IOException e) { try { ch.close(); } catch (IOException e2) { if (logger.isWarnEnabled()) { logger.warn( "Failed to close a partially initialized socket.", e2); } } throw new ChannelException("Failed to enter non-blocking mode.", e); } }
在AbstractNioChannel中做了下面幾件事:
1、繼續(xù)調(diào)用父類AbstractChannel(Channel parent)構(gòu)造方法;
2、通過this.ch = ch 保存ServerSocketChannel, 因?yàn)镹ioServerSocketChannel是Netty封裝的對(duì)象,而ServerSocketChannel是有前面默認(rèn)selector_provider生成的,是java nio的, 其實(shí)“this.ch = ch”可以被認(rèn)為是綁定java nio服務(wù)端通道至netty對(duì)象中;
3、設(shè)置ServerSocketChannel關(guān)心的事件類型;
4、設(shè)置ServerSocketChannel為非阻塞的(熟悉Java NIO的都知道如果不設(shè)置為false,啟動(dòng)多路復(fù)用器會(huì)報(bào)異常)
我們?cè)倏匆幌翧bstractChannel(Channel parent)的內(nèi)部代碼細(xì)節(jié)
protected AbstractChannel(Channel parent) { this.parent = parent; id = newId(); unsafe = newUnsafe(); pipeline = newChannelPipeline(); }
此構(gòu)造方法中,主要做了三件事:
1、給channel生成一個(gè)新的id
2、通過newUnsafe初始化channel的unsafe屬性
3、newChannelPipeline初始化channel的pipeline屬性
id的生成我們就不細(xì)究了,我們主要看看newUnsafe 及 newChannelPipeline是如何創(chuàng)建unsafe對(duì)象及pipeline對(duì)象的。
newUnsafe()方法調(diào)用
在AbstractChannel類中,newUnsafe()是一個(gè)抽象方法
protected abstract AbstractUnsafe newUnsafe();
通過上面的類繼承結(jié)構(gòu)圖,我們找到AbstractNioMessageChannel類中有newUnsafe()的實(shí)現(xiàn)
@Override protected AbstractNioUnsafe newUnsafe() { return new NioMessageUnsafe(); }
此方法返回一個(gè)NioMessageUnsafe實(shí)例對(duì)象,而NioMessageUnsafe是AbstractNioMessageChannel的內(nèi)部類
private final class NioMessageUnsafe extends AbstractNioUnsafe { private final List
NioMessageUnsafe 只覆蓋了 父類AbstractNioUnsafe中的read方法,通過NioMessageUnsafe 及其父類的代碼便可以知道, 其實(shí)unsafe對(duì)象是真正的負(fù)責(zé)底層channel的連接/讀/寫等操作的,unsafe就好比一個(gè)底層channel操作的代理對(duì)象。
newChannelPipeline()方法調(diào)用
newChannelPipeline直接在AbstractChannel內(nèi)實(shí)現(xiàn)
protected DefaultChannelPipeline newChannelPipeline() { return new DefaultChannelPipeline(this); }
該方法返回了創(chuàng)建了一個(gè)DefaultChannelPipeline對(duì)象
protected DefaultChannelPipeline(Channel channel) { this.channel = ObjectUtil.checkNotNull(channel, "channel"); succeededFuture = new SucceededChannelFuture(channel, null); voidPromise = new VoidChannelPromise(channel, true); tail = new TailContext(this); head = new HeadContext(this); head.next = tail; tail.prev = head; }
此DefaultChannelPipeline對(duì)象會(huì)綁定NioServerSocketChannel對(duì)象,并初始化了HeadContext及TailContext對(duì)象。
tail = new TailContext(this); head = new HeadContext(this);
head及tail初始化完成后,它們會(huì)相互連接。
通過上面的代碼可以得出,pipeline就是一個(gè)雙向鏈表。關(guān)于Pipeline的更多細(xì)節(jié),此處不做贅述,歡迎大家關(guān)注下一篇文章。
我們?cè)诨氐絅ioServerSocketChannel的構(gòu)造方法 NioServerSocketChannel(ServerSocketChannel channel)
public NioServerSocketChannel(ServerSocketChannel channel) { super(null, channel, SelectionKey.OP_ACCEPT); config = new NioServerSocketChannelConfig(this, javaChannel().socket()); }
父類構(gòu)造方法調(diào)用完成后,NioServerSocketChannel還要初始化一下自己的配置對(duì)象
config = new NioServerSocketChannelConfig(this, javaChannel().socket());
NioServerSocketChannelConfig是NioServerSocketChannel的內(nèi)部類
private final class NioServerSocketChannelConfig extends DefaultServerSocketChannelConfig { private NioServerSocketChannelConfig(NioServerSocketChannel channel, ServerSocket javaSocket) { super(channel, javaSocket); } @Override protected void autoReadCleared() { clearReadPending(); } }
而NioServerSocketChannelConfig 又是繼承自DefaultServerSocketChannelConfig,通過代碼分析,此config對(duì)象就是就會(huì)對(duì)底層ServerSocket一些配置設(shè)置行為的封裝。
至此NioServerSocketChannel對(duì)象應(yīng)該創(chuàng)建完成了~
總結(jié):
1、NioServerSocketChannel對(duì)象內(nèi)部綁定了Java NIO創(chuàng)建的ServerSocketChannel對(duì)象;2、Netty中,每個(gè)channel都有一個(gè)unsafe對(duì)象,此對(duì)象封裝了Java NIO底層channel的操作細(xì)節(jié);
3、Netty中,每個(gè)channel都有一個(gè)pipeline對(duì)象,此對(duì)象就是一個(gè)雙向鏈表;
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/68104.html
摘要:對(duì)于,目前大家只知道是個(gè)線程組,其內(nèi)部到底如何實(shí)現(xiàn)的,它的作用到底是什么,大家也都不太清楚,由于篇幅原因,這里不作詳細(xì)介紹,后面會(huì)有文章作專門詳解。 在上一篇《ServerBootstrap 與 Bootstrap 初探》中,我們已經(jīng)初步的了解了ServerBootstrap是netty進(jìn)行服務(wù)端開發(fā)的引導(dǎo)類。 且在上一篇的服務(wù)端示例中,我們也看到了,在使用netty進(jìn)行網(wǎng)絡(luò)編程時(shí),我...
摘要:在上一篇源碼實(shí)戰(zhàn)系列三全剖析中,我們?cè)敿?xì)分析了的初始化過程,并得出了如下結(jié)論在中,每一個(gè)都有一個(gè)對(duì)象,并且其內(nèi)部本質(zhì)上就是一個(gè)雙向鏈表本篇我們將深入源碼內(nèi)部,對(duì)其一探究竟,給大家一個(gè)全方位解析。 在上一篇《Netty4.x 源碼實(shí)戰(zhàn)系列(三):NioServerSocketChannel全剖析》中,我們?cè)敿?xì)分析了NioServerSocketChannel的初始化過程,并得出了如下結(jié)論...
摘要:而用于主線程池的屬性都定義在中本篇只是簡(jiǎn)單介紹了一下引導(dǎo)類的配置屬性,下一篇我將詳細(xì)介紹服務(wù)端引導(dǎo)類的過程分析。 從Java1.4開始, Java引入了non-blocking IO,簡(jiǎn)稱NIO。NIO與傳統(tǒng)socket最大的不同就是引入了Channel和多路復(fù)用selector的概念。傳統(tǒng)的socket是基于stream的,它是單向的,有InputStream表示read和Outpu...
摘要:下面無恥的貼點(diǎn)源碼。啟動(dòng)類我們也學(xué),把啟動(dòng)類抽象成兩層,方便以后寫客戶端。別著急,我們慢慢來,下一篇我們會(huì)了解以及他的成員,然后,完善我們的程序,增加其接收數(shù)據(jù)的能力。文章的源碼我會(huì)同步更新到我的上,歡迎大家,哈哈。 廢話兩句 這次更新拖了很長時(shí)間,第一是自己生病了,第二是因?yàn)樽铋_始這篇想寫的很大,然后構(gòu)思了很久,發(fā)現(xiàn)不太合適把很多東西寫在一起,所以做了點(diǎn)拆分,準(zhǔn)備國慶前完成這篇博客。...
摘要:接下來的兩篇文章,我將從源碼角度為大家深入淺出的剖析的線程模型工作機(jī)制。我們看一下的源碼通過的代碼發(fā)現(xiàn),實(shí)現(xiàn)了接口,其內(nèi)部會(huì)通過指定的默認(rèn)線程工廠來創(chuàng)建線程,并執(zhí)行相應(yīng)的任務(wù)。至此,初始化完成了。下一篇我們將詳細(xì)介紹,敬請(qǐng)期待。 我們都知道Netty的線程模型是基于React的線程模型,并且我們都知道Netty是一個(gè)高性能的NIO框架,那么其線程模型必定是它的重要貢獻(xiàn)之一。 在使用ne...
閱讀 3309·2021-11-18 10:02
閱讀 2755·2019-08-30 13:56
閱讀 416·2019-08-29 12:36
閱讀 527·2019-08-28 18:07
閱讀 716·2019-08-27 10:51
閱讀 3453·2019-08-26 12:13
閱讀 3291·2019-08-26 11:46
閱讀 3318·2019-08-23 12:00