Netty原始碼學習系列之2-ServerBootstrap的初始化

淡墨痕發表於2020-06-01

前言

    根據前文我們知道,NioEventLoopGroup和NioEventLoop是netty對Reactor執行緒模型的實現,而本文要說的ServerBootstrap是對上面二者的整合與呼叫,是一個統籌者和協調者。具體netty使用的是Reactor單執行緒模型還是多執行緒模型、抑或者主從多執行緒模型,都是ServerBootstrap的不同配置決定的。

    下面照例貼上一下示例demo(以Reactor多執行緒模式構建),開始正文。

 1 public class NettyDemo1 {
 2     // netty服務端的一般性寫法
 3     public static void main(String[] args) {
 4         EventLoopGroup boss = new NioEventLoopGroup(1);
 5         EventLoopGroup worker = new NioEventLoopGroup();
 6         try {
 7             ServerBootstrap bootstrap = new ServerBootstrap();
 8             bootstrap.group(boss, worker).channel(NioServerSocketChannel.class)
 9                     .option(ChannelOption.SO_BACKLOG, 100)
10                     .childHandler(new ChannelInitializer<SocketChannel>() {
11                         @Override
12                         protected void initChannel(SocketChannel socketChannel) throws Exception {
13                             ChannelPipeline pipeline = socketChannel.pipeline();
14                             pipeline.addLast(new StringDecoder());
15                             pipeline.addLast(new StringEncoder());
16                             pipeline.addLast(new NettyServerHandler());
17                         }
18                     });
19             ChannelFuture channelFuture = bootstrap.bind(90);
20             channelFuture.channel().closeFuture().sync();
21         } catch (Exception e) {
22             e.printStackTrace();
23         } finally {
24             boss.shutdownGracefully();
25             worker.shutdownGracefully();
26         }
27     }
28 }

 

一、ServerBootstrap的初始化

    ServerBootstrap的無參構造器啥都沒做,它使用的build模式給屬性賦值,即上面示例中看到的,每執行一個賦值方法都會返回當前物件的引用使得可以繼續鏈式呼叫。下面挨個方法追蹤。

1 public ServerBootstrap() { }

 

1、ServerBootstrap.group方法

    ServerBootstrap有兩個可用過載group方法(如下的兩個),其中接收一個group入參的方法會呼叫有兩個入參的group方法,只是兩個引數傳同一個group。這兩個group方法決定了netty使用的Reactor執行緒模型的型別,一個group入參的方法對應Reactor單執行緒模型,兩個入參且不是同一個group的方法對應Reactor多執行緒模型或主從多執行緒模型(具體是哪一種取決於例項化parentGroup時的執行緒數)。此處只是提一下,先有個印象,後面會對執行緒模型進行詳細研究。

1 public ServerBootstrap group(EventLoopGroup group) {
2         return group(group, group);
3     }
1 public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
2         super.group(parentGroup);
3         ObjectUtil.checkNotNull(childGroup, "childGroup");
4         if (this.childGroup != null) {
5             throw new IllegalStateException("childGroup set already");
6         }
7         this.childGroup = childGroup;
8         return this;
9     }

    可以看到上述group方法對兩個入參進行了不同位置的賦值,將第一個引數parentGroup傳給了父類AbstractBootstrap的group方法,如下,即最終賦值給了AbstractBootstrap中的group屬性。第二個引數直接賦值給了ServerBootstrap的childGroup屬性。

1 public B group(EventLoopGroup group) {
2         ObjectUtil.checkNotNull(group, "group");
3         if (this.group != null) {
4             throw new IllegalStateException("group set already");
5         }
6         this.group = group;
7         return self();
8     }

 

2、ServerBootstrap.option/childOption方法和ServerBootstrap.attr/childAttr方法

    這四個方法只是做了屬性的賦值,分別賦值給了AbstractBootstrap的options屬性和attrs屬性以及ServerBootstrap的childOptions屬性和childAttrs屬性。

 1 public <T> B option(ChannelOption<T> option, T value) {
 2         ObjectUtil.checkNotNull(option, "option");
 3         if (value == null) {
 4             synchronized (options) {
 5                 options.remove(option);
 6             }
 7         } else {
 8             synchronized (options) {
 9                 options.put(option, value);
10             }
11         }
12         return self();
13     }
 1 public <T> B attr(AttributeKey<T> key, T value) {
 2         ObjectUtil.checkNotNull(key, "key");
 3         if (value == null) {
 4             synchronized (attrs) {
 5                 attrs.remove(key);
 6             }
 7         } else {
 8             synchronized (attrs) {
 9                 attrs.put(key, value);
10             }
11         }
12         return self();
13     }

 

3、ServerBootstrap.channel方法

    呼叫的是父類AbstractBootstrap的channel方法:

1 public B channel(Class<? extends C> channelClass) {
2         return channelFactory(new ReflectiveChannelFactory<C>(
3                 ObjectUtil.checkNotNull(channelClass, "channelClass")
4         ));
5     }

    可以看到先封裝成了一個ReflectiveChannelFactory物件,然後呼叫channelFactory方法,下面挨個看。ReflectiveChannelFactory的構造器如下,可見就是將傳入class物件的構造器取出來賦值,此時constructor存放的就是NioServerSocketChannel的構造器。

public ReflectiveChannelFactory(Class<? extends T> clazz) {
        ObjectUtil.checkNotNull(clazz, "clazz");
        try {
            this.constructor = clazz.getConstructor();
        } catch (NoSuchMethodException e) {
            throw new IllegalArgumentException("Class " + StringUtil.simpleClassName(clazz) +
                    " does not have a public non-arg constructor", e);
        }
    }

    channelFactory方法的工作是將上面建立的ReflectiveChannelFactory物件賦值給AbstractBootstrap的channelFactory屬性:

1 public B channelFactory(ChannelFactory<? extends C> channelFactory) {
2         ObjectUtil.checkNotNull(channelFactory, "channelFactory");
3         if (this.channelFactory != null) {
4             throw new IllegalStateException("channelFactory set already");
5         }
6 
7         this.channelFactory = channelFactory;
8         return self();
9     }

 

4、ServerBootstrap.handler方法和ServerBootstrap.childHandler方法

    handler方法的入參賦值給了AbstractBootstrap的handler屬性,childHandler方法的入參賦值給了ServerBootstrap的childHandler屬性。看到這裡想必園友們也能看出ServerBootstrap的賦值規律了,凡是child開頭的都放在ServerBootstrap中,而不帶child的大多放在其父類ABstractBootstrap中。

1 public B handler(ChannelHandler handler) {
2         this.handler = ObjectUtil.checkNotNull(handler, "handler");
3         return self();
4     }
1 public ServerBootstrap childHandler(ChannelHandler childHandler) {
2         this.childHandler = ObjectUtil.checkNotNull(childHandler, "childHandler");
3         return this;
4     }

 

5、完成賦值後ServerBootstrap的快照圖

 

 

小結

    ServerBootstrap的初始化過程看起來賦了很多值,但都只是做了準備工作,看起來輕鬆又簡單,但請注意,這是暴風雨前寧靜。前面的各種賦值到底有什麼用處?很多屬性分為有child字首和沒有child字首,這樣設定又有什麼意圖?下一期將進入ServerBootstrap的bind方法,這是netty的深水區,很多謎底也將在這裡得到揭曉,敬請期待!

 

相關文章