1、服务端channel的创建和初始化流程
bind() 服务端绑定端口号
——> initAndRegister() 初始化并且注册
———— > newChannel() 创建服务端Channel
———— > init()初始化服务端channel
从bind进入:
ChannelFuture sync = bootstrap.bind(port).sync();
public ChannelFuture bind(int inetPort) {
return bind(new InetSocketAddress(inetPort));
}
public ChannelFuture bind(SocketAddress localAddress) {
validate(); //进行参数校验
if (localAddress == null) {
throw new NullPointerException("localAddress");
}
return doBind(localAddress); //重点-----------------------》详细解读
}
主要分析dobind()方法如下:
1、初始化一个channel实例
2、将配置信息和channel进行绑定
3、调用NIO的bind操作来绑定端口
private ChannelFuture doBind(final SocketAddress localAddress) {
//通过initAndRegister进行初始化和注册,可以知道是需要拿到channel通道的实例
final ChannelFuture regPromise = initAndRegister(); //----------》下面是详细解析
final Channel channel = regPromise.channel();
final ChannelPromise promise = channel.newPromise();
if (regPromise.isDone()) {
//端口绑定操作,最终是通过封装的NIO中的bind操作来完成端口的绑定
doBind0(regPromise, channel, localAddress, promise); // 这是NioEventLoop启动的关键方法
} else {
regPromise.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
doBind0(future, channel, localAddress, promise);
}
});
}
return promise;
}
initAndRegister()方法的部分代码:
final ChannelFuture initAndRegister() {
//通过分析channel实例是NIOServerSocketChannel类型的实例
final Channel channel = channelFactory().newChannel();//----------------重点 创建channel
try {
init(channel); //----------------------------》重点 初始化线程
} catch (Throwable t) {
channel.unsafe().closeForcibly();
return channel.newFailedFuture(t);
}
2、创建服务端channel: -------》channelFactoyr().newChannel 方法的详细解析
源码追踪:initAndRegister()---->channelFactoyr().newChannel
这个channelFactory()的类型对应Serverbootstrap.channel()方法 ;
此处的channel()传入的是NioServerSocketChanne.class,,继续跟源码,会发现他通过ReflectiveChannelFactory会通过反射创建出一个NioServreSokcetChannel对象来。
此处主要分析NioServerSocketChannel的构造方法:源码已看
此构造方法主要干了一下几件事:
newSocket 创建底层channel
NioServerSocketChannelConfig() //配置tcp中的参数
AbstbstractNioChannel()
configureBlockconfigureBlocking(false) ,//设置阻塞模式
AbstractChannel() // 配置channel的标志idunsafe,还有pipeline
3、服务端channel的初始化 init方法的解析
(1) 、setChannelOptions、ChannelAttrs (配置可选操作项,对应serverBootStrap中的 .option() 和 .attr()中的值 )
(2)、setChildOptions、childAttrs(配置子线程的可选操作,对应serverBootStrap中的.chileOption() 和 childAttr() 的值 )
(3) 、配置服务端的pipeline (对应的ServerBootStrap中的 handler() )
(4)、添加连接器(其实就是将childChannel作为一个ChannelHandler添加进主事件的pipeline中)
源码如下:
void init(Channel channel) throws Exception {
//1、setChannelOptions 和setChannelAttrs
//获取主事件循环的相关options的配置
final Map<ChannelOption<?>, Object> options = options();
synchronized (options) {
//通过同步操作将option配置信息配置到channel实例上
channel.config().setOptions(options);
}
//通过同步操作将attr配置信息配置到channel实例上
final Map<AttributeKey<?>, Object> attrs = attrs();
synchronized (attrs) {
for (Entry<AttributeKey<?>, Object> e: attrs.entrySet()) {
@SuppressWarnings("unchecked")
AttributeKey<Object> key = (AttributeKey<Object>) e.getKey();
channel.attr(key).set(e.getValue());
}
}
//chennel实例的pipeline()的实例,添加的是channelHandler的实例,一般不配置
ChannelPipeline p = channel.pipeline();
if (handler() != null) {
p.addLast(handler());
}
//2、 配置setChildOptions、childAttrs
final EventLoopGroup currentChildGroup = childGroup;
final ChannelHandler currentChildHandler = childHandler;
final Entry<ChannelOption<?>, Object>[] currentChildOptions;
final Entry<AttributeKey<?>, Object>[] currentChildAttrs;
synchronized (childOptions) {
currentChildOptions = childOptions.entrySet().toArray(newOptionArray(childOptions.size()));
}
synchronized (childAttrs) {
currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(childAttrs.size()));
}
//3 、 往主事件循环中添加的channelhandler,
p.addLast(new ChannelHandler[]{new ChannelInitializer<Channel>() {
public void initChannel(final Channel ch) throws Exception {
final ChannelPipeline pipeline = ch.pipeline();
ChannelHandler handler = ServerBootstrap.this.config.handler();
if (handler != null) {
pipeline.addLast(new ChannelHandler[]{handler});
}
//4、子事件循环组的group实例,options\handler等信息实例化了一个channelhandler
//即子事件循环组作为主事件循环组的一个channelhandler来处理channel
ch.eventLoop().execute(new Runnable() {
public void run() {
pipeline.addLast(new ChannelHandler[]{
new ServerBootstrap.ServerBootstrapAcceptor(ch, currentChildGroup,
currentChildHandler, currentChildOptions, currentChildAttrs)});
}
});
}
}});
}