57. Netty源代码分析-服务器端启动ServerBootstrap初始化
一. 开始
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() { @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继承关系图
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(channelClass)); }public B channelFactory(ChannelFactory extends C> channelFactory) { this.channelFactory = channelFactory; return self(); }public class ReflectiveChannelFactory implements ChannelFactory { 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) { } }}
上面这段代码可以看出:
- 初始化了一个ReflectiveChannelFactory工程类,它是一个工厂类,调用newChannel的时候负责初始化一个指定Channel。也就是我们传入进来的NioServerSocketChannel对象。
- 这个工厂对象保存在AbstractBootstrap的channelFactory属性里面,以便于后面调用生成channel对象,目前只是保存工厂对象。
继续看b.option()方法
2.5 设置option
Map, Object> options; public B option(ChannelOption 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; }
从上面代码可以看出:
- childHandler保存在ServerBootstrap,变量是childHandler,当然也是volatile类型的,我们传进来的类型是 ChannelInitializer,重写了它的initChannel方法。
- childHandler和handler都是ChannelHandler类型,不过一个在子类,一个在父类里面。
三. 总结
ServerBootstrap的初始化分析完之后,我们来总结下。
ServerBootstrap提供了一个无参构造函数,为了适应各种不同的场景。 它使用了构造者模式,构造者模式大家百度即可,比如: https://www.cnblogs.com/cc11001100/p/5939220.html
ServerBootstrap保存了
EventLoopGroup childGroup,在上面例子我们的类型是NioEventLoopGroup。
ChannelHandler childHandler;父类AbstractBootstrap保存了同一个类型的
volatile EventLoopGroup group;
private volatile ChannelHandler handler;- 到目前为止,我们只是初始化了所有的变量,为下一步bind做准备。bind的流程我们下篇继续分析。