EventLoopGroup
顾名思义,为事件循环组,可以理解为线程组,类似Filter、Intercept,都是循环链路
先看看类图:
可以看到最上层为Executor,接下层为ExecutorService,即线程池,印证了Event是通过线程来分发的,本质就是线程池
切入点中,new了一个NioEventLoopGroup,咱们来说道说道,直接看最深层的构造方法:
protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
EventExecutorChooserFactory chooserFactory, Object... args) {
if (executor == null) {
//初始化线程池
executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
}
//1. 创建一个大小为nThreads的SingleThreadEventExecutor数组
children = new EventExecutor[nThreads];
//2.初始化数组,每次循环都是new一个NioEventLoop
for (int i = 0; i < nThreads; i ++) {
boolean success = false;
try {
children[i] = newChild(executor, args);
success = true;
} 。。。
}
//3.根据nThreads的大小,创建不同的Chooser。
//即如果nThreads是2的幂,则使用PowerOfTwoEventExecutorChooser
//反之使用GenericEventExecutorChooser
//两者功能一致,都是从children数组中选择一个合适的EventExecutor实例
chooser = chooserFactory.newChooser(children);
final FutureListener<Object> terminationListener = new FutureListener<Object>() {
@Override
public void operationComplete(Future<Object> future) throws Exception {
if (terminatedChildren.incrementAndGet() == children.length) {
terminationFuture.setSuccess(null);
}
}
};
for (EventExecutor e: children) {
e.terminationFuture().addListener(terminationListener);
}
Set<EventExecutor> childrenSet = new LinkedHashSet<EventExecutor>(children.length);
Collections.addAll(childrenSet, children);
readonlyChildren = Collections.unmodifiableSet(childrenSet);
}
不断深入super的过程中出现的有:
SelectStrategyFactory:用来管理Nio中的Selector
DEFAULT_EVENT_LOOP_THREADS:默认事件循环数,涉及一个算法:
//Runtime.getRuntime().availableProcessors()获取运行时电脑有多少个cpu,即几核
//此处将线程池初始化为cpu的两倍
DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(
"io.netty.eventLoopThreads", Runtime.getRuntime().availableProcessors() * 2));
EventLoopGroup初始化过程总结:
group方法:
public B group(EventLoopGroup group) {
this.group = group;
return (B) this;
}
非常简单,就是将初始化后的EventLoopGroup放入Bootstrap中
option方法:
public <T> B option(ChannelOption<T> option, T value) {
if (value == null)
synchronized (options)
options.remove(option);
else
synchronized (options)
options.put(option, value);
return (B) this;
}
也非常简单,就是根据value是否为null,来选择是否加入options
handler方法
将需要的处理器、编码解码器等放入pipeline中,即真正的业务处理
我们实现了ChannelInitializer#InitChannel,那么这个方法是在哪里调用呢?是在ChannelInitializer#channelRegistered#initChannel中
public final void channelRegistered(ChannelHandlerContext ctx) throws Exception {
if (initChannel(ctx)) //模板模式
ctx.pipeline().fireChannelRegistered();
else
ctx.fireChannelRegistered();
}
private boolean initChannel(ChannelHandlerContext ctx) throws Exception {
initChannel((C) ctx.channel());//使用者重写的就是此方法
remove(ctx);
}
重写了之后,会调用fireChannelRegistered:
public final ChannelPipeline fireChannelRegistered() {
AbstractChannelHandlerContext.invokeChannelRegistered(head);
return this;
}
//此处代码很有美感
static void invokeChannelRegistered(final AbstractChannelHandlerContext next) {
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
next.invokeChannelRegistered();
} else {
executor.execute(new Runnable() {
@Override
public void run() {
next.invokeChannelRegistered();
}
});
}
}
回到initChannel中,看看remove方法,此方法通过finally来保证执行,是一种设计技巧:
private void remove(ChannelHandlerContext ctx) {
try {
ChannelPipeline pipeline = ctx.pipeline();
if (pipeline.context(this) != null) {
pipeline.remove(this);
}
} finally {
initMap.remove(ctx);
}
}
remove自己,即ChannelInitializer,因为它只是作为一个配置的模板,执行的时候不需要它的逻辑,删掉可以增加性能,这是一种很巧妙的设计技巧
看看流程图:
最后一个管道,即执行完handler方法后,pipeline的状态