當前位置:編程學習大全網 - 源碼下載 - Netty 源碼解析 ——— ChannelConfig 和 Attribute

Netty 源碼解析 ——— ChannelConfig 和 Attribute

嗯,本文與其說是ChannelConfig、Attribute源碼解析,不如說是對ChannelConfig以及Attribute結構層次的分析。因為這才是它們在Netty中使用到的重要之處。

在 Netty 源碼解析 ——— 服務端啟動流程 (下) 中說過,當我們在構建NioServerSocketChannel的時候同時會構建壹個NioServerSocketChannelConfig對象賦值給NioServerSocketChannel的成員變量config。

而這壹個NioServerSocketChannelConfig是當前NioServerSocketChannel配置屬性的集合。NioServerSocketChannelConfig主要用於對NioServerSocketChannel相關配置的設置(如,網絡的相關參數配置),比如,配置Channel是否為非阻塞、配置連接超時時間等等。

NioServerSocketChannelConfig其實是壹個ChannelConfig實例。ChannelConfig表示為壹個Channel相關的配置屬性的集合。所以NioServerSocketChannelConfig就是針對於NioServerSocketChannel的配置屬性的集合。

ChannelConfig是Channel所需的公***配置屬性的集合,如,setAllocator(設置用於channel分配buffer的分配器)。而不同類型的網絡傳輸對應的Channel有它們自己特有的配置,因此可以通過擴展ChannelConfig來補充特有的配置,如,ServerSocketChannelConfig是針對基於TCP連接的服務端ServerSocketChannel相關配置屬性的集合,它補充了針對TCP服務端所需的特有配置的設置setBacklog、setReuseAddress、setReceiveBufferSize。

DefaultChannelConfig作為ChannelConfig的默認實現,對ChannelConfig中的配置提供了默認值。

接下來,我們來看壹個設置ChannelConfig的流程:

serverBootstrap.option(ChannelOption.SO_REUSEADDR, true);

我們可以在啟動服務端前通過ServerBootstrap來進行相關配置的設置,該選項配置會在Channel初始化時被獲取並設置到Channel中,最終會調用底層ServerSocket.setReuseAddress方法來完成配置的設置。

ServerBootstrap的init()方法:

首先對option和value進行校驗,其實就是進行非空校驗。

然後判斷對應的是哪個常量屬性,並進行相應屬性的設置。如果傳進來的ChannelOption不是已經設定好的常量屬性,則會打印壹條警告級別的日誌,告知這是未知的channel option。

Netty提供ChannelOption的壹個主要的功能就是讓特定的變量的值給類型化。因為從’ChannelOption<T> option’和’T value’可以看出,我們屬性的值類型T,是取決於ChannelOption的泛型的,也就屬性值類型是由屬性來決定的。

這裏,我們可以看到有個ChannelOption類,它允許以類型安全的方式去配置壹個ChannelConfig。支持哪壹種ChannelOption取決於ChannelConfig的實際的實現並且也可能取決於它所屬的傳輸層的本質。

可見ChannelOption是壹個Consant擴展類,Consant是Netty提供的壹個單例類,它能安全去通過’==’來進行比較操作。通過ConstantPool進行管理和創建。

常量由壹個id和name組成。id:表示分配給常量的唯壹數字;name:表示常量的名字。

如上所說,Constant是由ConstantPool來進行管理和創建的,那麽ConstantPool又是個什麽樣的類了?

首先從constants中get這個name對應的常量,如果不存在則調用newConstant()來構建這個常量tempConstant,然後在調用constants.putIfAbsent方法來實現“如果該name沒有存在對應的常量,則插入,否則返回該name所對應的常量。(這整個的過程都是原子性的)”,因此我們是根據putIfAbsent方法的返回來判斷該name對應的常量是否已經存在於constants中的。如果返回為null,則說明當前創建的tempConstant就為name所對應的常量;否則,將putIfAbsent返回的name已經對應的常量值返回。(註意,因為ConcurrentHashMap不會允許value為null的情況,所以我們可以根據putIfAbsent返回為null則代表該name在此之前並未有對應的常量值)

正如我們前面所說的,這個ConstantPool<ChannelOption<Object>> pool(即,ChannelOption常量池)是ChannelOption的壹個私有靜態成員屬性,用於管理和創建ChannelOption。

這些定義好的ChannelOption常量都已經存儲數到ChannelOption的常量池(ConstantPool)中了。

註意,ChannelOption本身並不維護選項值的信息,它只是維護選項名字本身。比如,“public static final ChannelOption<Integer> SO_RCVBUF = valueOf("SO_RCVBUF");”?這只是維護了“SO_RCVBUF”這個選項名字的信息,同時泛型表示選擇值類型,即“SO_RCVBUF”選項值為Integer。

好了,到目前為止,我們對Netty的ChannelOption的設置以及底層的實現已經分析完了,簡單的來說:Netty在初始化Channel時會構建壹個ChannelConfig對象,而ChannelConfig是Channel配置屬性的集合。比如,Netty在初始化NioServerSocketChannel的時候同時會構建壹個NioServerSocketChannelConfig對象,並將其賦值給NioServerSocketChannel的成員變量config,而這個config(NioServerSocketChannelConfig)維護了NioServerSocketChannel的所有配置屬性。比如,NioServerSocketChannelConfig提供了setConnectTimeoutMillis方法來設置NioServerSocketChannel連接超時的時間。

同時,程序可以通過ServerBootstrap或Boostrap的option(ChannelOption<T> option, T value)方法來實現配置的設置。這裏,我們通過ChannelOption來實現配置的設置,ChannelOption中已經將常用的配置項預定義為了常量供我們直接使用,同時ChannelOption的壹個主要的功能就是讓特定的變量的值給類型化。因為從’ChannelOption<T> option’和’T value’可以看出,我們屬性的值類型T,是取決於ChannelOption的泛型的,也就屬性值類型是由屬性來決定的。

壹個attribute允許存儲壹個值的引用。它可以被自動的更新並且是線程安全的。

其實Attribute就是壹個屬性對象,這個屬性的名稱為AttributeKey<T> key,而屬性的值為T value。

我們可以通過程序ServerBootstrap或Boostrap的attr方法來設置壹個Channel的屬性,如:

serverBootstrap.attr(AttributeKey.valueOf("userID"), UUID.randomUUID().toString());

當Netty底層初始化Channel的時候,就會將我們設置的attribute給設置到Channel中:

如上面所說,Attribute就是壹個屬性對象,這個屬性的名稱為AttributeKey<T> key,而屬性的值為T value。

而AttributeKey也是Constant的壹個擴展,因此也有壹個ConstantPool來管理和創建,這和ChannelOption是類似的。

Channel類本身繼承了AttributeMap類,而AttributeMap它持有多個Attribute,這些Attribute可以通過AttributeKey來訪問的。所以,才可以通過channel.attr(key).set(value)的方式將屬性設置到channel中了(即,這裏的attr方法實際上是AttributeMap接口中的方法)。

AttributeKey、Attribute、AttributeMap間的關系:

AttributeMap相對於壹個map,AttributeKey相當於map的key,Attribute是壹個持有key(AttributeKey)和value的對象。因此在map中我們可以通過AttributeKey key獲取Attribute,從而獲取Attribute中的value(即,屬性值)。

Q:ChannelHandlerContext和Channel都提供了attr方法,那麽它們設置的屬性作用域有什麽不同了?

A:在Netty 4.1版本之前,它們兩設置的屬性作用域確實存在著不同,但從Netty 4.1版本開始,它們兩設置的屬性的作用域已經完全相同了。

若文章有任何錯誤,望大家不吝指教:)

聖思園《精通並發與Netty》

  • 上一篇:0和1表示的含義是什麽c語言
  • 下一篇:有關環保的壹些東西,文章小品影視詩歌~~~~任何都行!!!!加急
  • copyright 2024編程學習大全網