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 中里面有如下几个属性:
- ,NioEventLoopGroup (在父类 SingleThreadEventExecutor 中)
- ,selector
- ,provider
- ,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)
- ,handler:SimpleServerHandler
- ,childHandler
- ,option
- ,childOption
来源: https://www.cnblogs.com/java-chen-hao/p/11459808.html