Netty源码分析 (二)----- ServerBootstrap
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中里面有如下几个属性:
1、nioeventloopgroup (在父类singlethreadeventexecutor中)
2、selector
3、provider
4、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)
3、handler:simpleserverhandler
4、childhandler
5、option
6、childoption
推荐阅读
-
Netty源码分析 (四)----- ChannelPipeline
-
vuex源码分析(二) state及strict属性 详解
-
Netty源码分析 (三)----- 服务端启动源码分析
-
Tomcat源码分析 (九)----- HTTP请求处理过程(二)
-
jQuery 源码分析(二) 入口模块
-
STL源码分析之第二级配置器
-
Netty源码分析之ChannelPipeline(二)—ChannelHandler的添加与删除
-
Mybaits 源码解析 (九)----- 全网最详细,没有之一:一级缓存和二级缓存源码分析
-
Tomcat源码分析 (二)----- Tomcat整体架构及组件
-
Netty源码分析 (十)----- 拆包器之LineBasedFrameDecoder