温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

57. Netty源代码分析-服务器端启动ServerBootstrap初始化

发布时间:2020-07-08 13:39:14 来源:网络 阅读:1296 作者:rongwei84n 栏目:软件技术

一. 开始

1.1 上一篇

接上一篇NioEventLoopGroup的实例化分析继续
https://blog.51cto.com/483181/2118817

这篇博客要分析的是 “2. ServerBootstrap初始化”,如下:

EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap(); //2. ServerBootstrap初始化
            b.group(bossGroup, workerGroup) // 2. ServerBootstrap初始化
                .channel(NioServerSocketChannel.class)
                .option(ChannelOption.SO_BACKLOG, 100)
                .handler(new LoggingHandler(LogLevel.INFO))
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {

                    }
                });

            ChannelFuture f = b.bind(port).sync(); //3. bind
            f.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }

二. ServerBootstrap

2.1 ServerBootstrap继承关系图

57. Netty源代码分析-服务器端启动ServerBootstrap初始化

2.2 ServerBootstrap构造函数

public ServerBootstrap() { }

ServerBootstrap提供了一个无参构造函数,其实有点奇怪,因为像这种网络服务肯定要适应不同的场景,所以肯定得有很多参数的构造函数。
对于这一点,正是因为要适配的参数太多了,所以ServerBootstrap提供了一个无参构造函数,然后使用构造者模式来解决这个问题。
如下:

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

2.3 ServerBootstrap.group

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;
    }

父类的group(xx)

public B group(EventLoopGroup group) {
        this.group = group;
        return self();
    }

传入了两个EventLoopGroup,也就是上一篇文章说的NioEventLoopGroup,一个是bossGroup,一个workerGroup.
其中bossGroup存在它的父类group属性
workerGroup存在ServerBootstrap的childGroup属性里面,不过暂时不知道它们之间的区别。

继续看b.channel(NioServerSocketChannel.class)

2.4 设置channel

代码在ServerBootstrap的父类AbstractBootstrap里面,如下:

public B channel(Class<? extends C> channelClass) {
        return channelFactory(new ReflectiveChannelFactory<C>(channelClass));
    }

public B channelFactory(ChannelFactory<? extends C> channelFactory) {
        this.channelFactory = channelFactory;
        return self();
    }

public class ReflectiveChannelFactory<T extends Channel> implements ChannelFactory<T> {

    private final Class<? extends T> clazz;

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

    @Override
    public T newChannel() {
        try {
            return clazz.getConstructor().newInstance();
        } catch (Throwable t) {
        }
    }
}               

上面这段代码可以看出:

  1. 初始化了一个ReflectiveChannelFactory工程类,它是一个工厂类,调用newChannel的时候负责初始化一个指定Channel。也就是我们传入进来的NioServerSocketChannel对象。
  2. 这个工厂对象保存在AbstractBootstrap的channelFactory属性里面,以便于后面调用生成channel对象,目前只是保存工厂对象。

继续看b.option()方法

2.5 设置option

Map<ChannelOption<?>, Object> options; 

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 self();
    }

从上面这代码可以看出几点:
1.option方法带有remove和put两个操作,根据value是否null来判断。这种写法自己以前用的比较少,一般的话会提供两个方法出来。
2.如果是put的话,那么把值存在options这个Map集合里面。

继续回头看b.handler()方法

2.6 handler方法

handler方法位于ServerBootstrap的父类AbstractBootstrap里面,如下:

private volatile ChannelHandler handler;

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

很是简单,就是把传入的ChannelHandler对象保存起来,放在属性handler里面。
另外,注意到handler对象是volatile类型的,volatile具有挥发性,如果一个线程修改了数据,那么另外一个线程可以马上看到这个修改。具体大家可以百度下。

继续回去看b.childHandler(xx)方法

2.7 childHandler

childHandler方法位于ServerBootstrap里面

private volatile ChannelHandler childHandler;

public ServerBootstrap childHandler(ChannelHandler childHandler) {

                private volatile ChannelHandler childHandler;

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

从上面代码可以看出:

  1. childHandler保存在ServerBootstrap,变量是childHandler,当然也是volatile类型的,我们传进来的类型是 ChannelInitializer,重写了它的initChannel方法。
  2. childHandler和handler都是ChannelHandler类型,不过一个在子类,一个在父类里面。

三. 总结

ServerBootstrap的初始化分析完之后,我们来总结下。

  1. ServerBootstrap提供了一个无参构造函数,为了适应各种不同的场景。 它使用了构造者模式,构造者模式大家百度即可,比如: https://www.cnblogs.com/cc11001100/p/5939220.html

  2. ServerBootstrap保存了
    EventLoopGroup childGroup,在上面例子我们的类型是NioEventLoopGroup
    ChannelHandler childHandler;

  3. 父类AbstractBootstrap保存了同一个类型的
    volatile EventLoopGroup group;
    private volatile ChannelHandler handler;

  4. 到目前为止,我们只是初始化了所有的变量,为下一步bind做准备。bind的流程我们下篇继续分析。
向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI