把标题连在一起,就是这个服务启动所做的事情
- 初始化Channel并注册
- 初始化Channel
- 配置ChannelConfig的ChannelOptions
- 配置Attribute
- Pipeline添加ChannelHandler
- 注册过程
- 选择执行注册的EvenLoop
- 启动EventLoop
- 异步执行注册任务
- 注册到Selector
- 回调ChannelHandler的handlerAdded
- 回调ChannelInboundHandler的channelRegistered
- isActive决定是否回调ChannelInboundHandler的channelActive
- 异步绑定
- 回调HeadContext.bind方法
- NioServerSocketChannel的doBind实现
- isActive决定是否回调ChannelInboundHandler的channelActive
- 回调HeadContext.bind方法
- 初始化Channel
1 服务端启动Demo
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup,workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer() {
@Override
public void initChannel(SocketChannel ch)
throws Exception {
ch.pipeline().addLast(handlers);
}})
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
ChannelFuture f = b.bind(port).sync();
2 启动过程源码解读
为了方便阅读和理解,代码做了合并和简化,只保留核心代码
2.1 初始化Channel并注册
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
channel = channelFactory.newChannel();
init(channel);
} catch (Throwable t) {
// XXX
}
ChannelFuture regFuture = config().group().register(channel);
if (regFuture.cause() != null) {
// XXX
}
return regFuture;
}
2.1.1 初始化Channel
2.1.1.1 配置ChannelConfig的ChannelOptions
final Map, Object> options = options0();
synchronized (options) {
for (Map.Entry, Object> e: options.entrySet()) {
channel.config().setOption((ChannelOption
2.1.1.2 配置Attribute
final Map, Object> attrs = attrs0();
synchronized (attrs) {
for (Entry, Object> e: attrs.entrySet()) {
AttributeKey
2.1.1.3 Pipeline添加ChannelHandler
ChannelPipeline p = channel.pipeline();
p.addLast(new ChannelInitializer() {
@Override
public void initChannel(final Channel ch) throws Exception {
// 添加用户定义的ChannelHandler
final ChannelPipeline pipeline = ch.pipeline();
ChannelHandler handler = config.handler();
if (handler != null) {
pipeline.addLast(handler);
}
// 异步添加ServerBootstrapAcceptor
ch.eventLoop().execute(new Runnable() {
@Override
public void run() {
pipeline.addLast(new ServerBootstrapAcceptor(
ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}
});
}
});
也许你对 ServerBootstrapAcceptor 很感兴趣,那么请延后了解,因为我们本篇文章主要在探究Netty服务加载的过程。
请记住,如果赋予一件事情过多的目的,那么这件事情一定会失败
2.1.2 注册过程
2.1.2.1 选择执行注册的EvenLoop
public EventExecutorChooser newChooser(EventExecutor[] executors) {
// 非常巧妙,利用补码特性判断2的幂次,此处加鸡腿
// (val & -val) == val
if (isPowerOfTwo(executors.length)) {
return new PowerOfTwoEventExecutorChooser(executors);
} else {
return new GenericEventExecutorChooser(executors);
}
}
- PowerOfTwoEventExecutorChooser
executors[idx.getAndIncrement() & executors.length - 1]
- GenericEventExecutorChooser
executors[Math.abs(idx.getAndIncrement() % executors.length
2.1.2.2 启动EventLoop
public void execute(Runnable task) {
// 添加任务到队列
addTask(task);
executor.execute(new Runnable() {
@Override
public void run() {
try {
// 执行EvenLoop的run方法
SingleThreadEventExecutor.this.run();
} catch (Throwable t) {
// XXX
} finally {
// 循环执行队列中任务
}
});
}
}
2.1.2.3异步执行注册任务
private void register0(ChannelPromise promise) {
try {
doRegister();
pipeline.invokeHandlerAddedIfNeeded();
pipeline.fireChannelRegistered();
if (isActive()) {
if (firstRegistration) {
pipeline.fireChannelActive();
} else if (config().isAutoRead()) {
beginRead();
}
}
} catch (Throwable t) {
// Close the channel directly to avoid FD leak.
}
}
2.1.2.3.1 注册到Selector
- AbstractNioUnsafe的实现
protected void doRegister() throws Exception {
boolean selected = false;
for (;;) {
try {
selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
return;
} catch (CancelledKeyException e) {
if (!selected) {
// Force the Selector to select now as the "canceled" SelectionKey may still be
// cached and not removed because no Select.select(..) operation was called yet.
eventLoop().selectNow();
selected = true;
} else {
// We forced a select operation on the selector before but the SelectionKey is still cached
// for whatever reason. JDK bug ?
throw e;
}
}
}
}
2.1.2.3.2 回调ChannelHandler的handlerAdded
final void invokeHandlerAddedIfNeeded() {
assert channel.eventLoop().inEventLoop();
if (firstRegistration) {
firstRegistration = false;
PendingHandlerCallback task = pendingHandlerCallbackHead;
while (task != null) {
if (executor.inEventLoop()) {
ctx.setAddComplete();
ctx.handler().handlerAdded(ctx);
} else {
// 异步执行
}
task = task.next;
}
}
}
2.1.2.3.3 回调ChannelInboundHandler的channelRegistered
@Override
public final ChannelPipeline fireChannelRegistered() {
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
invokeChannelRegistered : if (invokeHandler()) {
try {
((ChannelInboundHandler) handler()).channelRegistered(this);
}
} else {
// 查找下一个Handler
AbstractChannelHandlerContext ctx = this;
do {
ctx = ctx.next;
} while (!ctx.inbound);
EventExecutor executor2 = ctx.executor();
if (executor2.inEventLoop()) {
ctx.invokeChannelRegistered();
} else {
// 异步执行
});
}
} else {
// 异步执行
}
}
2.1.2.3.4 isActive决定是否回调ChannelInboundHandler的channelActive
@Override
public final ChannelPipeline fireChannelActive() {
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
invokeChannelActive : if (invokeHandler()) {
try {
((ChannelInboundHandler) handler()).channelActive(this);
}
} else {
AbstractChannelHandlerContext ctx = this;
do {
ctx = ctx.next;
} while (!ctx.inbound);
if (ctx.executor().inEventLoop()) {
ctx.invokeChannelActive();
} else {
// 异步执行
}
}
} else {
// 异步处理
}
}
2.2 异步绑定
2.2.1 回调HeadContext.bind方法
@Override
public void bind(
ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise)
throws Exception {
unsafe.bind(localAddress, promise);
}
2.2.1.1 NioServerSocketChannel的doBind实现
@Override
protected void doBind(SocketAddress localAddress) throws Exception {
if (PlatformDependent.javaVersion() >= 7) {
javaChannel().bind(localAddress, config.getBacklog());
} else {
javaChannel().socket().bind(localAddress, config.getBacklog());
}
}
2.2.1.2 isActive决定是否回调ChannelInboundHandler的channelActive
事实上,在执行doBind操作后,isActive才为true,所以channelActive实在这一步回调的
if (!wasActive && isActive()) {
invokeLater(new Runnable() {
@Override
public void run() {
pipeline.fireChannelActive();
}
});
}