上篇博客《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类的无参的构造函数赋值给ReflectiveChannelFactory
的constructor
的属性。具体如下图所示:
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
,如果传入的值不为空的话,我们就将该值put
到options
中去,最后返回当前对象,便于链式的调用。这个时候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
类初始化到赋值就结束了。下篇博客我会介绍服务端启动的流程的源码。