Netty源码(二)之ServerBootstrap初始化的过程

上篇博客《Netty源码(一)之NioEventLoopGroup初始化的过程》我们说了NioEventLoopGoup的初始化的过程。今天我们来讲讲ServerBootstrap的初始化的过程,我们继续重现上篇博客的代码,具体的代码如下:

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;

//服务端
public class NettyServer {
    public static void main(String[] args) throws InterruptedException {
        //就是一个死循环,不停地检测IO事件,处理IO事件,执行任务
        //创建一个线程组:接受客户端连接   主线程
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);//cpu核心数*2
        //创建一个线程组:接受网络操作   工作线程
        EventLoopGroup workerGroup = new NioEventLoopGroup();  //cpu核心数*2

        //是服务端的一个启动辅助类,通过给他设置一系列参数来绑定端口启动服务
        ServerBootstrap serverBootstrap = new ServerBootstrap();

        // 我们需要两种类型的人干活,一个是老板,一个是工人,老板负责从外面接活,
        // 接到的活分配给工人干,放到这里,bossGroup的作用就是不断地accept到新的连接,将新的连接丢给workerGroup来处理
        serverBootstrap.group(bossGroup, workerGroup)
                //设置使用NioServerSocketChannel作为服务器通道的实现
                .channel(NioServerSocketChannel.class)
                .option(ChannelOption.SO_BACKLOG, 128) //设置线程队列中等待连接的个数
                .childOption(ChannelOption.SO_KEEPALIVE, true)//保持活动连接状态
                //表示服务器启动过程中,需要经过哪些流程,这里NettyTestHandler最终的顶层接口为ChannelHandler,
                // 是netty的一大核心概念,表示数据流经过的处理器
                .handler(new NettyTestHendler())
                //表示一条新的连接进来之后,该怎么处理,也就是上面所说的,老板如何给工人配活
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
                        nioSocketChannel.pipeline().addLast(new StringDecoder(), new NettyServerHendler());
                    }
                });
        System.out.println(".........server  init..........");
        // 这里就是真正的启动过程了,绑定9090端口,等待服务器启动完毕,才会进入下行代码
        ChannelFuture future = serverBootstrap.bind(9090).sync();
        System.out.println(".........server start..........");
        //等待服务端关闭socket
        future.channel().closeFuture().sync();

        // 关闭两组死循环
        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
    }
}

今天我们讲的代码具体是下面的一部分:

//是服务端的一个启动辅助类,通过给他设置一系列参数来绑定端口启动服务
ServerBootstrap serverBootstrap = new ServerBootstrap();
// 我们需要两种类型的人干活,一个是老板,一个是工人,老板负责从外面接活,
// 接到的活分配给工人干,放到这里,bossGroup的作用就是不断地accept到新的连接,将新的连接丢给workerGroup来处理
serverBootstrap.group(bossGroup, workerGroup)
  //设置使用NioServerSocketChannel作为服务器通道的实现
  .channel(NioServerSocketChannel.class)
  .option(ChannelOption.SO_BACKLOG, 128) //设置线程队列中等待连接的个数
  .childOption(ChannelOption.SO_KEEPALIVE, true)//保持活动连接状态
  //表示服务器启动过程中,需要经过哪些流程,这里NettyTestHandler最终的顶层接口为ChannelHandler,
  // 是netty的一大核心概念,表示数据流经过的处理器
  .handler(new NettyTestHendler())
  //表示一条新的连接进来之后,该怎么处理,也就是上面所说的,老板如何给工人配活
  .childHandler(new ChannelInitializer<NioSocketChannel>() {
    @Override
    protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
      nioSocketChannel.pipeline().addLast(new StringDecoder(), new NettyServerHendler());
    }
  });

上面的new ServerBootstrap();代码只是单纯的创建了一个ServerBootstrap()类,没有做任何事件,具体的赋值的代码还是在下面的链式的调用。我们先看serverBootstrap.group(bossGroup, workerGroup)方法,这儿传的两个参数,第一个参数是监听客户端连接的NioEventLoopGroup,第二个参数是处理客户端事件的NioEventLoopGroup。让我们打开group方法,一探究竟吧。打开的代码如下所示:

public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel> {
  //parentGroup监听客户端连接的EventLoopGroup
  //childGroup处理客户端事件的EventLoopGroup
  public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
    		//首先调用的是父类的group方法,我们继续跟进去看看
        super.group(parentGroup);
        ObjectUtil.checkNotNull(childGroup, "childGroup");
        if (this.childGroup != null) {
            throw new IllegalStateException("childGroup set already");
        }
        this.childGroup = childGroup;
        return this;
    }
}

上面的group方法首先调用的是父类的group的方法。我们先打开父类的group方法。具体的代码如下:

public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
  public B group(EventLoopGroup group) {
        ObjectUtil.checkNotNull(group, "group");
        if (this.group != null) {
            throw new IllegalStateException("group set already");
        }
        // 处理的用户连接的  group=new NioEventLoopGroup();
        this.group = group;
        return self();
    }
}

上面的代码主要赋值,然后返回当前的对象,便于后面的链式的调用。这个时候AbstractBootstrap类具体的结构如下图所示:

在这里插入图片描述

在这里插入图片描述

上面的两张图应该是整合在一起的。其中NioEventLoop是继承的SingleThreadEventLoop,而SingleThreadEventLoop是继承SingleThreadEventExecutor所以NioEventLoop中有SingleThreadEventExecutor的属性,所以最终的样子就是把SingleThreadEventExecutor中的属性移动到NioEventLoop中去,让两张图进行对应的整合,就得到了AbstractBootstrap类的样子。AbstractBootstrap类的赋值结束后,我们继续查看ServerBootstrap中的group方法,具体的代码如下:

public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel> {
  //parentGroup监听客户端连接的EventLoopGroup
  //childGroup处理客户端事件的EventLoopGroup
  public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
    		//父类的方法调用返回
        super.group(parentGroup);
        ObjectUtil.checkNotNull(childGroup, "childGroup");
        if (this.childGroup != null) {
            throw new IllegalStateException("childGroup set already");
        }
    		//子类进行赋值,这个时候ServerBootstrap和上面的差不多。
        this.childGroup = childGroup;
        return this;
    }
}

这个时候ServerBootstrap中的childGroup进行对应的赋值,具体如下图所示:

在这里插入图片描述

在这里插入图片描述

同样是两张图的合体。和AbstractBootstrap类差不多。到此我们的group方法就看完了,我们继续看调用链中后续的方法。具体的代码如下:

serverBootstrap.group(bossGroup, workerGroup)
  //设置使用NioServerSocketChannel作为服务器通道的实现
  .channel(NioServerSocketChannel.class)
  .option(ChannelOption.SO_BACKLOG, 128) //设置线程队列中等待连接的个数
  .childOption(ChannelOption.SO_KEEPALIVE, true)//保持活动连接状态
  //表示服务器启动过程中,需要经过哪些流程,这里NettyTestHandler最终的顶层接口为ChannelHandler,
  // 是netty的一大核心概念,表示数据流经过的处理器
  .handler(new NettyTestHendler())
  //表示一条新的连接进来之后,该怎么处理,也就是上面所说的,老板如何给工人配活
  .childHandler(new ChannelInitializer<NioSocketChannel>() {
    @Override
    protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
      nioSocketChannel.pipeline().addLast(new StringDecoder(), new NettyServerHendler());
    }
  });

我们继续查看channel(NioServerSocketChannel.class)方法。打开对应的源码如下:

public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
  //泛型B  为  ServerBootstrap  C  为  ServerChannel
  public B channel(Class<? extends C> channelClass) {
    //channelClass=NioServerSocketChannel.class
    //首先调用的new ReflectiveChannelFactory<C>(ObjectUtil.checkNotNull(channelClass, "channelClass")
    return channelFactory(new ReflectiveChannelFactory<C>(
      ObjectUtil.checkNotNull(channelClass, "channelClass")
    ));
  }
}

首先调用的是new ReflectiveChannelFactory<C>(ObjectUtil.checkNotNull(channelClass, "channelClass")的方法,我们打开对应的方法,具体的代码如下:

public class ReflectiveChannelFactory<T extends Channel> implements ChannelFactory<T> {
    private final Constructor<? extends T> constructor;
    public ReflectiveChannelFactory(Class<? extends T> clazz) {
        //判断不为空
        ObjectUtil.checkNotNull(clazz, "clazz");
        try {
            //clazz=NioServerSocketChannel.class
            //constructor=NioServerSocketChannel.class.getConstructor();
            this.constructor = clazz.getConstructor();
        } catch (NoSuchMethodException e) {
            throw new IllegalArgumentException("Class " + StringUtil.simpleClassName(clazz) +
                    " does not have a public non-arg constructor", e);
        }
    }
}

可以发现上面的代码就是将传进来的class类的无参的构造函数赋值给ReflectiveChannelFactoryconstructor的属性。具体如下图所示:

在这里插入图片描述

ReflectiveChannelFactory中属性和方法就如上图所示,当该方法执行完后,就直接执行channelFactory方法,具体的代码如下所示:

public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
  //泛型B  为  ServerBootstrap  C  为  ServerChannel
  public B channel(Class<? extends C> channelClass) {
    //channelClass=NioServerSocketChannel.class
    //首先调用的new ReflectiveChannelFactory<C>(ObjectUtil.checkNotNull(channelClass, "channelClass")
    return channelFactory(new ReflectiveChannelFactory<C>(
      ObjectUtil.checkNotNull(channelClass, "channelClass")
    ));
  }
  public B channelFactory(io.netty.channel.ChannelFactory<? extends C> channelFactory) {
        //channelFactory=new ReflectiveChannelFactory
        return channelFactory((ChannelFactory<C>) channelFactory);
  }
  public B channelFactory(ChannelFactory<? extends C> channelFactory) {
        ObjectUtil.checkNotNull(channelFactory, "channelFactory");
        if (this.channelFactory != null) {
            throw new IllegalStateException("channelFactory set already");
        }
        //channelFactory=new ReflectiveChannelFactory
        this.channelFactory = channelFactory;
        return self();
   }
}

最后一样是给AbstractBootstrap对象的channelFactory属性进行对应的赋值,这个时候AbstractBootstrap如下图所示:

在这里插入图片描述

这个时候AbstractBootstrap就变成了上图的样子,最后这个channel方法就执行完成。并返回了自己,方面继续链式调用,我们继续查看链式调用的后续的方法option(ChannelOption.SO_BACKLOG, 128)。具体的代码如下所示:

serverBootstrap.group(bossGroup, workerGroup)
  //设置使用NioServerSocketChannel作为服务器通道的实现
  .channel(NioServerSocketChannel.class)
  .option(ChannelOption.SO_BACKLOG, 128) //设置线程队列中等待连接的个数
  .childOption(ChannelOption.SO_KEEPALIVE, true)//保持活动连接状态
  //表示服务器启动过程中,需要经过哪些流程,这里NettyTestHandler最终的顶层接口为ChannelHandler,
  // 是netty的一大核心概念,表示数据流经过的处理器
  .handler(new NettyTestHendler())
  //表示一条新的连接进来之后,该怎么处理,也就是上面所说的,老板如何给工人配活
  .childHandler(new ChannelInitializer<NioSocketChannel>() {
    @Override
    protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
      nioSocketChannel.pipeline().addLast(new StringDecoder(), new NettyServerHendler());
    }
  });

我们继续查看option(ChannelOption.SO_BACKLOG, 128)方法,让我们点开对应的源码,具体的源码如下:

public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
	public <T> B option(ChannelOption<T> option, T value) {
        //options=new LinkedHashMap<ChannelOption<?>, Object>();
        ObjectUtil.checkNotNull(option, "option");
        if (value == null) {
            synchronized (options) {
                options.remove(option);
            }
        } else {
            synchronized (options) {
                options.put(option, value);
            }
        }
        return self();
    }
}

这个时候,我们可以知道,如果传入的值为空的话,我们就直接从原来的options删除我们传入的option,如果传入的值不为空的话,我们就将该值putoptions中去,最后返回当前对象,便于链式的调用。这个时候AbstractBootstrap变成下图的样子。

在这里插入图片描述

options可以设置的参数如下图所示:

在这里插入图片描述

这个时候options方法也执行完了,最后返回的是自己,继续链式调用,继续执行childOption(ChannelOption.SO_KEEPALIVE, true)方法具体的代码如下所示:

serverBootstrap.group(bossGroup, workerGroup)
  //设置使用NioServerSocketChannel作为服务器通道的实现
  .channel(NioServerSocketChannel.class)
  .option(ChannelOption.SO_BACKLOG, 128) //设置线程队列中等待连接的个数
  .childOption(ChannelOption.SO_KEEPALIVE, true)//保持活动连接状态
  //表示服务器启动过程中,需要经过哪些流程,这里NettyTestHandler最终的顶层接口为ChannelHandler,
  // 是netty的一大核心概念,表示数据流经过的处理器
  .handler(new NettyTestHendler())
  //表示一条新的连接进来之后,该怎么处理,也就是上面所说的,老板如何给工人配活
  .childHandler(new ChannelInitializer<NioSocketChannel>() {
    @Override
    protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
      nioSocketChannel.pipeline().addLast(new StringDecoder(), new NettyServerHendler());
    }
  });

这个时候,我们打开childOption(ChannelOption.SO_KEEPALIVE, true)方法的源码,具体如下:

public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel> {
  public <T> ServerBootstrap childOption(ChannelOption<T> childOption, T value) {
    //childOptions=new LinkedHashMap<ChannelOption<?>, Object>();
    ObjectUtil.checkNotNull(childOption, "childOption");
    if (value == null) {
      synchronized (childOptions) {
        childOptions.remove(childOption);
      }
    } else {
      synchronized (childOptions) {
        childOptions.put(childOption, value);
      }
    }
    return this;
  }
}
  • options方法一样,只不过保存的对象的不同,上面的方法执行完后,这个时候ServerBootstrap类如下图所示:

在这里插入图片描述

childOption可以设置的参数和上面的option的设置的参数是一样的。这个时候childOption方法执行完,返回的自己,便于链式调用,这个时候调用的handler方法,具体的代码如下:

serverBootstrap.group(bossGroup, workerGroup)
  //设置使用NioServerSocketChannel作为服务器通道的实现
  .channel(NioServerSocketChannel.class)
  .option(ChannelOption.SO_BACKLOG, 128) //设置线程队列中等待连接的个数
  .childOption(ChannelOption.SO_KEEPALIVE, true)//保持活动连接状态
  //表示服务器启动过程中,需要经过哪些流程,这里NettyTestHandler最终的顶层接口为ChannelHandler,
  // 是netty的一大核心概念,表示数据流经过的处理器
  .handler(new NettyTestHendler())
  //表示一条新的连接进来之后,该怎么处理,也就是上面所说的,老板如何给工人配活
  .childHandler(new ChannelInitializer<NioSocketChannel>() {
    @Override
    protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
      nioSocketChannel.pipeline().addLast(new StringDecoder(), new NettyServerHendler());
    }
  });

这个时候执行handler(new NettyTestHendler())方法,在看源码之前,我们先看看NettyTestHendler类,具体的代码如下:

@ChannelHandler.Sharable
public class NettyTestHendler extends ChannelInboundHandlerAdapter{

    //通道准备就绪事件
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("channelActive-----"+ctx);
    }

    //读取数据事件
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if(msg instanceof NioSocketChannel){
            System.out.println(msg.getClass());
            ctx.fireChannelRead(msg);
            return;
        }
        ByteBuf byteBuf= (ByteBuf) msg;
        System.out.println("channelRead:"+byteBuf.toString(CharsetUtil.UTF_8));
    }

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


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

}

这个时候我们查看handler方法的源码,具体如下所示:

public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
	public B handler(ChannelHandler handler) {
        this.handler = ObjectUtil.checkNotNull(handler, "handler");
        return self();
    }
}

上面的操作一样是赋值,将我们写好的类赋值给AbstractBootstrap中的handler属性,然后AbstractBootstrap变成如下图所示:

在这里插入图片描述

这个时候handler方法就执行完成了,同时返回的是当前对象,方便继续链式调用。我们继续查看后续的方法childHandler(),具体的代码如下:

serverBootstrap.group(bossGroup, workerGroup)
  //设置使用NioServerSocketChannel作为服务器通道的实现
  .channel(NioServerSocketChannel.class)
  .option(ChannelOption.SO_BACKLOG, 128) //设置线程队列中等待连接的个数
  .childOption(ChannelOption.SO_KEEPALIVE, true)//保持活动连接状态
  //表示服务器启动过程中,需要经过哪些流程,这里NettyTestHandler最终的顶层接口为ChannelHandler,
  // 是netty的一大核心概念,表示数据流经过的处理器
  .handler(new NettyTestHendler())
  //表示一条新的连接进来之后,该怎么处理,也就是上面所说的,老板如何给工人配活
  .childHandler(new ChannelInitializer<NioSocketChannel>() {
    @Override
    protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
      nioSocketChannel.pipeline().addLast(new StringDecoder(), new NettyServerHendler());
    }
  });

这个时候我们点开childHandler()方法的源码,具体的源码如下:

public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel> {
  public ServerBootstrap childHandler(ChannelHandler childHandler) {
        // this.childHandler=new ChannelInitializer<ServerSocketChannel>()
        this.childHandler = ObjectUtil.checkNotNull(childHandler, "childHandler");
        return this;
    }
}

和上面的handler差不多,同样都是赋值,赋完值后ServerBootstrap如下图所示:

在这里插入图片描述

到此整个ServerBootstrap类初始化到赋值就结束了。下篇博客我会介绍服务端启动的流程的源码。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值