转载请注明来源
前言
Netty是什么,能做什么,业务场景啥的我就不写了,其实实际上是我这半吊子都没有的水平,啥也说不出来,写文章主要是做个笔记,巩固自己这段时间学习netty的心得,并把自己这个时间点对netty的理解写下来。
本章以debug方式跟踪代码,把netty在server端启动这个过程的流程,执行了什么逻辑给展示出来。
正文
这里选取了一个Time服务器的代码(有兴趣的可以自行去找官方的demo)作为debug演示,代码如下:
TimeServer.java
public class TimeServer {
private final int port = 8080;
public void run() throws InterruptedException {
/**
* bossGroup 和 workerGroup是两个独立的Reactor线程池,
* bossGroup负责客户端请求的accept操作,workerGroup负责处
* 理I/O相关的读写操作或者处理其它任务
*/
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.localAddress(new InetSocketAddress(port))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch)
throws Exception {
ch.pipeline().addLast(new TimeServerHandler());
}
}).option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
ChannelFuture f = b.bind().sync();
f.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully().sync();
workerGroup.shutdownGracefully().sync();
}
}
public static void main(String[] args) throws InterruptedException {
new TimeServer().run();
}
}
NioEventLoopGroup
这里从NioEventLoopGroup的初始化开始,NioEventLoopGroup主要负责管理eventLoop的生命周期,eventLoop数量默认为处理器个数的两倍。
debug开始,经过了NioEventLoopGroup的几个内部构造函数,来到了调用父类构造函数的位置:
public NioEventLoopGroup(int nEventLoops, Executor executor, final SelectorProvider selectorProvider) {
super(nEventLoops, executor, selectorProvider);
}
跳入父类MultithreadEventLoopGroup构造函数中:
虽然还是执行的是父类构造函数,但是我们可以看到这个参数 DEFAULT_EVENT_LOOP_THREADS 即默认的eventLoop个数为8个(本机是4核处理器),正如上面讲的eventLoop数量默认为处理器个数的两倍,继续跳入父类MultithreadEventExecutorGroup构造函数中(MultithreadEventExecutorGroup是核心,管理eventLoop的生命周期),
private MultithreadEventExecutorGroup(int nEventExecutors,
Executor executor,
boolean shutdownExecutor,
Object... args) {
if (nEventExecutors <= 0) {
throw new IllegalArgumentException(
String.format("nEventExecutors: %d (expected: > 0)", nEventExecutors));
}
if (executor == null) {
executor = newDefaultExecutorService(nEventExecutors);
shutdownExecutor = true;
}
//children:EventExecutor数组,保存eventLoop
//chooser:从children中选取一个eventLoop的策略
children = new EventExecutor[nEventExecutors];
//根据数组的大小,采取不同的策略初始化chooser
if (isPowerOfTwo(children.length)) {
//判断是否是2的幂次方
chooser = new PowerOfTwoEventExecutorChooser();
} else {
chooser = new GenericEventExecutorChooser();
}
for (int i = 0; i < nEventExecutors; i ++) {
boolean success = false;
try {
//初始化eventExecutor
children[i] = newChild(executor, args);
success = true;
} catch (Exception e) {
// TODO: Think about if this is a good exception type
throw new IllegalStateException("failed to create a child event loop", e);
} finally {
if (!success) {
for (int j = 0; j < i; j ++) {
children[j].shutdownGracefully();
}
for (int j = 0; j < i; j ++) {
EventExecutor e = children[j];
try {
while (!e.isTerminated()) {
e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
}
} catch (InterruptedException interrupted) {
// Let the caller handle the interruption.
Thread.currentThread().interrupt();
break;
}
}
}
}
}
final boolean shutdownExecutor0 = shutdownExecutor;
final Executor executor0 = executor;
final FutureListener<Object> terminationListener = new FutureListener<Object>() {
@Override
public void operationComplete(Future<Object> future) throws Exception {
if (terminatedChildren.incrementAndGet() == children.length) {
terminationFuture.setSuccess(null);
if (shutdownExecutor0) {
// This cast is correct because shutdownExecutor0 is only try if
// executor0 is of type ExecutorService.
((ExecutorService) executor0).shutdown();
}
}
}
};
for (EventExecutor e: children) {
e.terminationFuture().addListener(terminationListener);
}
Set<EventExecutor> childrenSet = new LinkedHashSet<EventExecutor>(children.length);
Collections.addAll(childrenSet, children);
readonlyChildren = Collections.unmodifiableSet(childrenSet);
}
这里我对几个重要的地方都做了相应的注释,方便理解。
程序继续执行,在children[i] = newChild(executor, args);处进入newChild方法,这里实际上是跳入了子类NioEven