Netty分布式Server啟動(dòng)流程服務(wù)端初始化源碼分析
第一節(jié):服務(wù)端初始化
首先看下在我們用戶代碼中netty的使用最簡單的一個(gè)demo:
//創(chuàng)建boss和worker線程(1) EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup(); //創(chuàng)建ServerBootstrap(2) ServerBootstrap b = new ServerBootstrap(); //初始化boss和work線程化兩個(gè)線程(3) b.group(bossGroup, workerGroup) //聲明NioServerSocketChannel(4) .channel(NioServerSocketChannel.class) //初始化客戶端Handler(5) .childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) { ch.pipeline().addLast(new StringDecoder()); ch.pipeline().addLast(new StringEncoder()); ch.pipeline().addLast(new ServerHandler()); } }); //綁定端口(6) ChannelFuture f = b.bind(8888).sync(); f.channel().closeFuture().sync();
相信這段代碼使用過netty的同學(xué)應(yīng)該都不陌生.這里每一步都用了注釋和步驟序號(hào)進(jìn)行標(biāo)注, 為了方便學(xué)習(xí)過程中更容易的定位.每一步的講解, 盡量自己也去跟到源碼中, 這樣會(huì)有個(gè)更深刻的理解
第一步, 創(chuàng)建兩個(gè)線程組:
其中會(huì)調(diào)用NioEventLoopGroup()的構(gòu)造方法, 其中的創(chuàng)建邏輯, 并不是這章的重點(diǎn), 在這里大家只需要知道這里創(chuàng)建了兩個(gè)線程組
第二步, 創(chuàng)建ServerBootstrap, 我們發(fā)現(xiàn), 這里創(chuàng)建只調(diào)用了其無參的構(gòu)造方法, 原因很簡單, 就是參數(shù)太多, 盡量要用構(gòu)造方法去初始化, 而是使用后面的build的方式
第三步, 初始化boss和work線程化兩個(gè)線程
group方法
我們跟到group方法中去看:
public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) { //設(shè)置線程池組 super.group(parentGroup); this.childGroup = childGroup; return this; }
為了代碼可讀性, 去掉非關(guān)鍵代碼(以后不再贅述), 我們看到這里初始化了自家的屬性childGroup, 而這個(gè)屬性就是我們傳入的worker線程組, 而boss線程組則交給了其父類的group方法去做處理
我們點(diǎn)進(jìn)去super.group(parentGroup), 進(jìn)入到ServerBootstroop的父類AbstractBootstrap的group()方法:
public B group(EventLoopGroup group) { this.group = group; return (B) this; }
看到在其父類初始化了boss線程
我們看到這個(gè)方法返回了this, 也就是ServerBootstroop自身, 這樣通過自身對(duì)象不斷的build進(jìn)行屬性初始化, 之后的方法也是如此
至此, worker和boss兩個(gè)線程組初始化完畢
初始化成員變量
回到最開始的第四步, 再點(diǎn)進(jìn)到channel(ServerSocketChannel.class)方法當(dāng)中,
我們看到AbsractServerBootstrap的channel(Class<? extends C> channelClass)方法:
public B channel(Class<? extends C> channelClass) { return channelFactory(new ReflectiveChannelFactory<C>(channelClass)); }
我們看到這個(gè)這返回的是channelFactory(new ReflectiveChannelFactory<C>(channelClass))方法, 并且傳入一個(gè)ReflectiveChannelFactory對(duì)象的實(shí)例,
我們可以跟進(jìn)去看下ReflectiveChannelFactory的構(gòu)造方法:
public ReflectiveChannelFactory(Class<? extends T> clazz) { this.clazz = clazz; }
這里初始化了一個(gè)成員變量clazz, 而這個(gè)clazz就是用戶代碼調(diào)用channel(NioServerSocketChannel.class)傳入的NioServerSocketChannel的class對(duì)象
回到channelFactory(new ReflectiveChannelFactory<C>(channelClass))方法, 點(diǎn)進(jìn)去, 我們看到:
public B channelFactory(io.netty.channel.ChannelFactory<? extends C> channelFactory) { return channelFactory((ChannelFactory<C>) channelFactory); }
繼續(xù)跟:
public B channelFactory(io.netty.channel.ChannelFactory<? extends C> channelFactory) { return channelFactory((ChannelFactory<C>) channelFactory); }
跟到最后:
public B channelFactory(ChannelFactory<? extends C> channelFactory) { this.channelFactory = channelFactory; return (B) this; }
這里初始化了channelFactory, 而這個(gè)channelFactory就是剛才創(chuàng)建的ReflectiveChannelFactory對(duì)象, 這里我們記住這個(gè)對(duì)象中初始化了我們的NioServerSocket的class對(duì)象
至此, 我們的ServerSocketChannel的class對(duì)象初始化完成
初始化客戶端Handler
我們跟到最開始的第五步, 初始化客戶端Handler:
.childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) { ch.pipeline().addLast(new StringDecoder()); ch.pipeline().addLast(new StringEncoder()); ch.pipeline().addLast(new ServerHandler()); } });
childHandler()方法比看起來比較復(fù)雜, 其實(shí)不難理解, 就是傳入ChannelInitializer類子類的一個(gè)對(duì)象(有關(guān)匿名內(nèi)部類不知道的同學(xué)可以找下相關(guān)資料學(xué)習(xí)下), 也就是一個(gè)Handler, 這個(gè)Handler是做什么的, 目前不需要關(guān)心, 以后會(huì)講到, 這里我們只需知道這個(gè)方法傳入一個(gè)handler對(duì)象
我們點(diǎn)進(jìn)childHandler這個(gè)方法:
public ServerBootstrap childHandler(ChannelHandler childHandler) { this.childHandler = childHandler; return this; }
發(fā)現(xiàn)同樣非常簡單的初始化了handler屬性
這一小節(jié)至此結(jié)束, 只是初始化了ServerBootstrap的各個(gè)屬性, 是不是非常簡單
我們可以看到, 通過對(duì)象build的方式, 可以初始化非常多的屬性, 并且代碼要比構(gòu)造方法的方式可讀性要好的多, 同學(xué)們可以將這種思想用在自己的代碼當(dāng)中...
以上就是Netty源碼分析Server啟動(dòng)流程的詳細(xì)內(nèi)容,更多關(guān)于NettyServer啟動(dòng)流程的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java實(shí)現(xiàn)XML增加元素操作簡單示例
這篇文章主要介紹了java實(shí)現(xiàn)XML增加元素操作,結(jié)合簡單實(shí)例形式分析了java針對(duì)xml格式數(shù)據(jù)的讀取、遍歷、創(chuàng)建等操作技巧,需要的朋友可以參考下2017-02-02spring boot整合log4j2及MQ消費(fèi)處理系統(tǒng)日志示例
這篇文章主要為大家介紹了spring boot整合log4j2及MQ消費(fèi)處理系統(tǒng)日志的示例過程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-03-03親手教你IDEA2020.3創(chuàng)建Javaweb項(xiàng)目的步驟詳解
這篇文章主要介紹了IDEA2020.3創(chuàng)建Javaweb項(xiàng)目的步驟詳解,本文是小編手把手教你,通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2021-03-03java 發(fā)送http和https請(qǐng)求的實(shí)例
下面小編就為大家分享一篇java 發(fā)送http和https請(qǐng)求的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-01-01關(guān)于@PostConstruct、afterPropertiesSet和init-method的執(zhí)行順序
這篇文章主要介紹了關(guān)于@PostConstruct、afterPropertiesSet和init-method的執(zhí)行順序,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09APP轉(zhuǎn)盤抽獎(jiǎng)Java服務(wù)端接口詳解
這篇文章主要為大家詳細(xì)介紹了APP轉(zhuǎn)盤抽獎(jiǎng)Java服務(wù)端接口,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01SpringBoot使用CXF集成WebService的方法
這篇文章主要介紹了SpringBoot使用CXF集成WebService的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08springboot項(xiàng)目同時(shí)啟動(dòng)web服務(wù)和grpc服務(wù)的方法
本文主要介紹了springboot項(xiàng)目同時(shí)啟動(dòng)web服務(wù)和grpc服務(wù)的方法,通過實(shí)際代碼示例展示了實(shí)現(xiàn),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-02-02