文章目录
- 1.ServerBootstrap
- 2.服务端启动过程
- 3.具体步骤分析
- 3.1 创建服务端Channel
- 3.2 初始化服务端Channel
- 3.3 注册selector
- 3.4 端口绑定
- 3.5 服务端的读事件
1.ServerBootstrap
ServerBootstrap引导服务端启动流程:
//主EventLoopGroup
NioEventLoopGroup master = new NioEventLoopGroup();
//从EventLoopGroup
NioEventLoopGroup worker = new NioEventLoopGroup();
//服务端引导类
ServerBootstrap bootstrap = new ServerBootstrap();
//配置主从EventLoopGroup
bootstrap.group(master, worker);
//channel选项配置
bootstrap.option(ChannelOption.SO_KEEPALIVE, true)
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS,5000);
bootstrap.channel(NioServerSocketChannel.class);
//主EventLoopGroup ChannelHandler配置
bootstrap.handler(new ChannelInboundHandlerAdapter(){
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
System.out.println("Master:" + ctx.channel().eventLoop().toString());
super.channelRegistered(ctx);
}
});
//从EventLoopGroup ChannelHandler配置
bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
System.out.println("Child:" + ch.eventLoop().toString());
}
});
//调用bind方法开始监听端口8888
ChannelFuture future = bootstrap.bind(8888).sync();
future.channel().closeFuture().sync();
master.shutdownGracefully().sync();
以上代码使用的是Netty框架中经典的主从事件驱动模式
2.服务端启动过程
-
main方法调用ServerBootstrap.bind()方法
-
validate()方法验证必要配置参数
-
调用AbstractBootstrap.initAndRegister()方法
-
调用channelFactory.newChannel()方法创建Channel实例
-
ServerBootstrap.init()初始化Channel实例,配置ChannelOption、attributes;在Channel的pipeline中配置默认的ChannelHandler实例
-
将Channel实例注册到主EventLoopGroup中并返回ChannelFuture
-
注册ChannelFuture回调,在完成后调用channel.bind()方法完成端口监听
3.具体步骤分析
1.创建服务端Channel
2.初始化服务端Channel
3.注册Selector
4.端口绑定
5.触发读事件
3.1 创建服务端Channel
AbstractBootstrap.bind()
- validate(): 验证必要配置参数
- AbstractBootstrap.doBind()
AbstractBootstrap.initAndRegister()
- 利用反射创建Channel, 得到NioServerSocketChannel
- 初始化channel中的一些参数
AbstractBootstrap.channel() 反射创建Channel
利用反射创建channel, 得到ReflectiveChannelFactory
, 调用channelFactory利用工厂模式, 最后生成NioServerSocketChannel
3.2 初始化服务端Channel
ServerBootstrap.init() 初始化一些基本参数
初始化一些Options和Attrs和group和handler的参数
@Override
void init(Channel channel) throws Exception {
final Map<ChannelOption<?>, Object> options = options0();
synchronized (options) {
setChannelOptions(channel, options, logger);
}
final Map<AttributeKey<?>, Object> attrs = attrs0();
synchronized (attrs) {
for (Entry<AttributeKey<?>, Object> e: attrs.entrySet()) {
@SuppressWarnings("unchecked")
AttributeKey<Object> key = (AttributeKey<Object>) e.getKey();
channel.attr(key).set(e.getValue());
}
}
ChannelPipeline p = channel.pipeline();
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(0));
}
synchronized (childAttrs) {
currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(0));
}
p.addLast(new ChannelInitializer<Channel>() {
@Override
public void initChannel(final Channel ch) throws Exception {
final ChannelPipeline pipeline = ch.pipeline();
ChannelHandler handler = config.handler();
if (handler != null) {
pipeline.addLast(handler);
}
ch.eventLoop().execute(new Runnable() {
@Override
public void run() {
pipeline.addLast(new ServerBootstrapAcceptor(
ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}
});
}
});
}
设置 currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs
在Channel的pipeline中配置默认的ChannelHandler实例
ServerBootstrapAcceptor 添加连接器, ServerBootstrapAcceptor本质是一个handler
3.3 注册selector
bind -> initAndRegister -> AbstractChannel.register -> this.eventLoop = eventLoop, register0 实际注册 -> doRegister(), invokeHandlerAddedIfNeeded(), fireChannelRegistered() 传播事件
AbstractChannel.AbstractUnsafe.register()
register0()
AbstractNioChannel.doRegister()
上面有javaChannel.register(), 利用jdk底层去创建selector
3.4 端口绑定
bind() -> doBind() -> doBind0() -> AbstracChannel,bind() -> DefaultChannelPipeline.bind() -> AbstractChannlHandlerContext.bind() -> AbstractChannlHandlerContext.invokeBind() -> DefaultChannelPipeline.HeadContext.bind() -> NioSocketChannel.doBind0(), pipeline.fireChannelActive();
最后将会调用DefaultChannelPipeline.HeadContext.bind(), 因为DefaultChannelPipeline在初始化时会设置pipeline队列的首尾分别为DefaultChannelPipeline.HeadContext与DefaultChannelPipeline.TailContext
bind()在Pipeline中走的是出站方法,是从管道的后面向前走,最后到达管道头部的ChannelHandler(也就是DefaultChannelPipeline.HeadContext),这一过程会调用同一方向上所有ChannelHandler的bind()事件。
AbstractBootstrap.doBind0(): 添加一个任务至EventLoop中, 最后将会调用DefaultChannelPipeline.HeadContext.bind()方法
AbstractChannlHandlerContext.invokeBind()
DefaultChannelPipeline.HeadContext.bind() -> AbstractChannel.AbstractUnsafe.bind()
@Override
public final void bind(final SocketAddress localAddress, final ChannelPromise promise) {
assertEventLoop();
if (!promise.setUncancellable() || !ensureOpen(promise)) {
return;
}
boolean wasActive = isActive();
try {
doBind(localAddress);
} catch (Throwable t) {
safeSetFailure(promise, t);
closeIfClosed();
return;
}
if (!wasActive && isActive()) {
invokeLater(new Runnable() {
@Override
public void run() {
pipeline.fireChannelActive();
}
});
}
safeSetSuccess(promise);
}
- NioSocketChannel.doBind() -> NioSocketChannel.doBind0()
- pipeline.fireChannelActive()
通过在pipline中的层层传递, 现在来到了最终执行bind操作的终点, 执行bind方法,
可以通过SocketUtils.bind() 绑定JDK底层的端口
3.5 服务端的读事件
最后如果触发了一个事件的话, 会调用Channel.read()事件(AbstractNioChannel.doBeginRead()), 这个事件对于服务端来说就是一个新的连接接入。
AbstractChannel.AbstractUnsafe.bind()
HeadContext.channelActive()
这个tail.read(), 触发的是beginRead()方法
AbstractUnsafe.beginRead()
AbstractNioChannel.doBeginRead()
这里的readInterestOp就是Acept事件
服务端端口绑定成功, 触发一个Acept事件, 然后调用channel.read()事件, 对于服务端来说就相当于可以读了, 可以读取一个新的连接。