Netty源碼分析 (二)----- ServerBootstrap


BootStrap在netty的應用程序中負責引導服務器和客戶端。netty包含了兩種不同類型的引導:
1. 使用服務器的ServerBootStrap,用於接受客戶端的連接以及為已接受的連接創建子通道。
2. 用於客戶端的BootStrap,不接受新的連接,並且是在父通道類完成一些操作。

一般服務端的代碼如下所示:

SimpleServer.java

/**
 * Created by chenhao on 2019/9/4.
 */
public final class SimpleServer {

    public static void main(String[] args) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .handler(new SimpleServerHandler())
                    .childHandler(new SimpleServerInitializer())
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);

            ChannelFuture f = b.bind(8888).sync();

            f.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

SimpleServerHandler.java

private static class SimpleServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("channelActive");
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        System.out.println("channelRegistered");
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        System.out.println("handlerAdded");
    }
}

SimpleServerInitializer.java

public class SimpleServerInitializer extends ChannelInitializer<SocketChannel>{

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();

        pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
        pipeline.addLast("decoder", new StringDecoder());
        pipeline.addLast("encoder", new StringEncoder());
        pipeline.addLast("handler", new SimpleChatServerHandler());

        System.out.println("SimpleChatClient:" + ch.remoteAddress()+"連接上");
    }
}

在上篇博文(Netty源碼分析 (一)----- NioEventLoopGroup)中 剖析了如下的兩行代碼內部的構造函數中干了些什么。

EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();

具體可以見上篇博文,對於如上的兩行代碼得到的結論是:

1、 如果不指定線程數,則線程數為:CPU的核數*2

2、根據線程個數是否為2的冪次方,采用不同策略初始化chooser

3、產生nThreads個NioEventLoop對象保存在children數組中。

可以理解NioEventLoop就是一個線程,線程NioEventLoop中里面有如下幾個屬性:

1、NioEventLoopGroup (在父類SingleThreadEventExecutor中)

2、selector

3、provider

4、thread (在父類SingleThreadEventExecutor中)

更通俗點就是: NioEventLoopGroup就是一個線程池,NioEventLoop就是一個線程。NioEventLoopGroup線程池中有N個NioEventLoop線程。

ServerBootstrap類分析

本篇博文將分析如下幾行代碼里面做了些什么。

ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .handler(new SimpleServerHandler())
                .childHandler(new SimpleServerInitializer())
                .option(ChannelOption.SO_BACKLOG, 128)
                .childOption(ChannelOption.SO_KEEPALIVE, true);

ServerBootstrap類的繼承結構如下:

該類的參數,有必要列出:

private final Map<ChannelOption<?>, Object> childOptions = new LinkedHashMap<ChannelOption<?>, Object>();
private final Map<AttributeKey<?>, Object> childAttrs = new LinkedHashMap<AttributeKey<?>, Object>();
private volatile EventLoopGroup childGroup;
private volatile ChannelHandler childHandler; 

其父類AbstractBootstrap的參數

private volatile EventLoopGroup group;
private volatile ChannelFactory<? extends C> channelFactory;
private volatile SocketAddress localAddress;
private final Map<ChannelOption<?>, Object> options = new LinkedHashMap<ChannelOption<?>, Object>();
private final Map<AttributeKey<?>, Object> attrs = new LinkedHashMap<AttributeKey<?>, Object>();
private volatile ChannelHandler handler;  

下面主要看下這個鏈式設置相關的參數。

group(bossGroup, workerGroup)

public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
    super.group(parentGroup);
    if (childGroup == null) {
        throw new NullPointerException("childGroup");
    }
    if (this.childGroup != null) {
        throw new IllegalStateException("childGroup set already");
    }
    this.childGroup = childGroup;
    return this;
}

即將workerGroup保存在 ServerBootstrap對象的childGroup屬性上。 bossGroup保存在ServerBootstrap對象的group屬性上

channel(NioServerSocketChannel.class)

public B channel(Class<? extends C> channelClass) {
    if (channelClass == null) {
        throw new NullPointerException("channelClass");
    }
    return channelFactory(new BootstrapChannelFactory<C>(channelClass));
} 
public B channelFactory(ChannelFactory<? extends C> channelFactory) {
    if (channelFactory == null) {
        throw new NullPointerException("channelFactory");
    }
    if (this.channelFactory != null) {
        throw new IllegalStateException("channelFactory set already");
    }

    this.channelFactory = channelFactory;
    return (B) this;
} 

函數功能:設置父類屬性channelFactory 為: BootstrapChannelFactory類的對象。其中這里BootstrapChannelFactory對象中包括一個clazz屬性為:NioServerSocketChannel.class,從如下該類的構造函數中可以明顯的得到這一點。

private static final class BootstrapChannelFactory<T extends Channel> implements ChannelFactory<T> {
    private final Class<? extends T> clazz;

    BootstrapChannelFactory(Class<? extends T> clazz) {
        this.clazz = clazz;
    }

    @Override
    public T newChannel() {
        try {
            return clazz.newInstance();
        } catch (Throwable t) {
            throw new ChannelException("Unable to create Channel from class " + clazz, t);
        }
    }

    @Override
    public String toString() {
        return StringUtil.simpleClassName(clazz) + ".class";
    }
}

並且BootstrapChannelFactory中提供 newChannel()方法,我們可以看到 clazz.newInstance(),主要是通過反射來實例化NioServerSocketChannel.class

handler(new SimpleServerHandler())

public B handler(ChannelHandler handler) {
    if (handler == null) {
        throw new NullPointerException("handler");
    }
    this.handler = handler; return (B) this;
}

注意:這里的handler函數的入參類是我們自己提供的。如下,后面的博文中將會分析這個handler將會在哪里以及何時被調用,這里只需要記住這一點即可

private static class SimpleServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("channelActive");
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        System.out.println("channelRegistered");
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        System.out.println("handlerAdded");
    }
}

childHandler(new SimpleServerInitializer())

public ServerBootstrap childHandler(ChannelHandler childHandler) {
    if (childHandler == null) {
        throw new NullPointerException("childHandler");
    }
    this.childHandler = childHandler;
    return this;
}

由最后一句可知,其實就是講傳入的childHandler賦值給ServerBootstrap的childHandler屬性。

該函數的主要作用是設置channelHandler來處理客戶端的請求的channel的IO。 這里我們一般都用ChannelInitializer這個類的實例或則繼承自這個類的實例
這里我是通過新建類SimpleChatServerInitializer繼承自ChannelInitializer。具體的代碼如下:

public class SimpleChatServerInitializer extends ChannelInitializer<SocketChannel>{

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();

        pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
        pipeline.addLast("decoder", new StringDecoder());
        pipeline.addLast("encoder", new StringEncoder());
        pipeline.addLast("handler", new SimpleChatServerHandler());

        System.out.println("SimpleChatClient:" + ch.remoteAddress()+"連接上");
    }
}

我們再看看ChannelInitializer這個類的繼承圖可知ChannelInitializer其實就是繼承自ChannelHandler的 

 

可知,這個類其實就是往pipeline中添加了很多的channelHandler。

配置ServerBootstrap的option

這里調用的是父類的AbstractBootstrap的option()方法,源碼如下:

public <T> B option(ChannelOption<T> option, T value) {
    if (option == null) {
        throw new NullPointerException("option");
    }
    if (value == null) {
        synchronized (options) {
            options.remove(option);
        }
    } else {
        synchronized (options) {
            options.put(option, value);
        }
    }
    return (B) this;
}

其中最重要的一行代碼就是:
options.put(option, value);
這里用到了options這個參數,在AbstractBootstrap的定義如下:
private final Map<ChannelOption<?>, Object> options = new LinkedHashMap<ChannelOption<?>, Object>();
可知是私有變量,而且是一個Map集合。這個變量主要是設置TCP連接中的一些可選項,而且這些屬性是作用於每一個連接到服務器被創建的channel。

配置ServerBootstrap的childOption

這里調用的是父類的ServerBootstrap的childOption()方法,源碼如下:

public <T> ServerBootstrap childOption(ChannelOption<T> childOption, T value) {
    if (childOption == null) {
        throw new NullPointerException("childOption");
    }
    if (value == null) {
        synchronized (childOptions) {
            childOptions.remove(childOption);
        }
    } else {
        synchronized (childOptions) {
            childOptions.put(childOption, value);
        }
    }
    return this;
}

這個函數功能與option()函數幾乎一樣,唯一的區別是該屬性設定只作用於被acceptor(也就是boss EventLoopGroup)接收之后的channel。

總結

比較簡單哈,主要是將我們提供的參數設置到其相應的對象屬性中去了。 因為后面會用到如下的幾個屬性,因此最好知道下,這些屬性是何時以及在那里賦值的。

1、group:workerGroup保存在 ServerBootstrap對象的childGroup屬性上。 bossGroup保存在ServerBootstrap對象的group屬性上

2、channelFactory:BootstrapChannelFactory類的對象(clazz屬性為:NioServerSocketChannel.class)

3、handler:SimpleServerHandler

4、childHandler

5、option

6、childOption


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM