Netty源码分析基于主流的Netty4.x版本。
继续围绕之前demo,本篇主要看看bind方法里面initAndRegister。
一.doBind流程概述
略过中间跳转,进入AbstractBootstrap的doBind方法
private ChannelFuture doBind(final SocketAddress localAddress) {
// 初始化配置并注册
final ChannelFuture regFuture = initAndRegister();
final Channel channel = regFuture.channel();
// 有异常返回
if (regFuture.cause() != null) {
return regFuture;
}
// 注册初始化执行完成
if (regFuture.isDone()) {
ChannelPromise promise = channel.newPromise();
doBind0(regFuture, channel, localAddress, promise);
return promise;
} else {
// 注册未完成
final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
// 添加监听完成事件
regFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
// 有异常封装到promise返回
Throwable cause = future.cause();
if (cause != null) {
promise.setFailure(cause);
} else {
// 注册成功
promise.registered();
doBind0(regFuture, channel, localAddress, promise);
}
}
});
return promise;
}
}
二.initAndRegister
initAndRegister 主要做三件事:
- 实例化Channel
- 初始化配置
- 注册对应的事件
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
// 这里是NioServerSocketChannel
// 对应demo中的channel(NioServerSocketChannel.class)设置
channel = channelFactory.newChannel();
// 这里由ServerBootstrap实现
init(channel);
} catch (Throwable t) {
...
}
ChannelFuture regFuture = config().group().register(channel);
// 有异常的处理
...
return regFuture;
}
三. 实例化NioServerSocketChannel
上文的channelFactory.newChannel()实例化NioServerSocketChannel
// 反射实例化,首先调用该无参构造
public NioServerSocketChannel() {
this(newSocket(DEFAULT_SELECTOR_PROVIDER));
}
public NioServerSocketChannel(ServerSocketChannel channel) {
super(null, channel, SelectionKey.OP_ACCEPT);
// 用于存储配置信息
config = new NioServerSocketChannelConfig(this, javaChannel().socket());
}
NioServerSocketChannel 设置了OP_ACCEPT参数,表示它会处理接收事件。
protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
super(parent);
this.ch = ch;
this.readInterestOp = readInterestOp;
try {
// channel设置为非阻塞的模式
ch.configureBlocking(false);
} catch (IOException e) {
...
}
}
再往上调用AbstractChannel的构造
protected AbstractChannel(Channel parent) {
this.parent = parent;
id = newId();
unsafe = newUnsafe();
// 创建了DefaultChannelPipeline对象
pipeline = newChannelPipeline();
DefaultChannelPipeline是一个双向链表,有前后指针。这里还创建了两个空的头尾节点。
protected DefaultChannelPipeline(Channel channel) {
this.channel = ObjectUtil.checkNotNull(channel, "channel");
succeededFuture = new SucceededChannelFuture(channel, null);
voidPromise = new VoidChannelPromise(channel, true);
tail = new TailContext(this);
head = new HeadContext(this);
head.next = tail;
tail.prev = head;
}
小结下重要地方:
- 设置channel对OP_ACCEPT事件感兴趣
- 设置channel为非堵塞模式
- 实例化了DefaultChannelPipeline,并建立了首尾节点
四. 初始化配置
init 方法主要配置之前demo中添加的配置信息,其中最关键的是添加ServerBootstrapAcceptor。
当前的NioServerSocketChannel只负责接受客户端连接。当有连接进来,会创建一个NioSocketChannel,ServerBootstrapAcceptor会将NioSocketChannel注册到workGroup(专门处理IO事件)中,并将复制这些预设的子group、子handler配置
@Override
void init(Channel channel) throws Exception {
// 这里的options数据来源于option设置
// 例如demo中的option(ChannelOption.SO_BACKLOG, 128)
final Map<ChannelOption<?>, Object> options = options0();
synchronized (options) {
// 向NioServerSocketChannel中设置option参数
setChannelOptions(channel, options, logger);
}
// 数据来源attr操作,类似options
final Map<AttributeKey<?>, Object> attrs = attrs0();
synchronized (attrs) {
for (Entry<AttributeKey<?>, Object> e: attrs.entrySet()) {
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;
// 数据来源类似option操作
synchronized (childOptions) {
currentChildOptions = childOptions.entrySet().toArray(newOptionArray(0));
}
// 数据来源类似option操作
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));
}
});
}
});
}
接着看看addLast方法在ChannelPipeline中做了哪些操作。
public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
final AbstractChannelHandlerContext newCtx;
synchronized (this) {
checkMultiplicity(handler);
// filterName方法会生成一个不重复的名称,返回ClassName#0的格式
// 如果有Class名称一致则#后的数字会往上累加至不重复位置
// 将handler包装到上下文newContext中,后续还会关联executor
newCtx = newContext(group, filterName(name, handler), handler);
// 更新双向链表节点指向
addLast0(newCtx);
// 首次还未注册,执行上文p.addLast(new ChannelInitializer)进入这里
if (!registered) {
// 设置上下文状态为等待添加
newCtx.setAddPending();
// 将任务放入pendingHandlerCallbackHead中稍后在执行
callHandlerCallbackLater(newCtx, true);
return this;
}
EventExecutor executor = newCtx.executor();
// 当前线程是否与NioEventLoop关联线程一致,如果不一致,开启executor对应得出线程执行任务
if (!executor.inEventLoop()) {
// 内部执行executor.execute(()->callHandlerAdded0(newCtx))
callHandlerAddedInEventLoop(newCtx, executor);
return this;
}
}
// 当前线程与NioEventLoop关联线程一致,直接执行
callHandlerAdded0(newCtx);
return this;
}
executor.inEventLoop()这个是干嘛的?
这里Netty是实现channel操作无锁化串行的关键。将每个channel的操作都关联到对应的线程执行,这样子避免了线程安全问题,而且也避免上下文切换的开销。
到目前为止管道中只有一个处理器
五. 注册处理器
register调用的是MultithreadEventLoopGroup的方法
public ChannelFuture register(Channel channel) {
return next().register(channel);
}
这里的next()是调用上篇介绍的EventExecutorChooserFactory的方法,实际返回一个NioEventLoop对象。
NioEventLoop是SingleThreadEventLoop的子类,故而register调用的是SingleThreadEventLoop的方法。
public ChannelFuture register(Channel channel) {
// channel这里实际是NioServerSocketChannel
return register(new DefaultChannelPromise(channel, this));
}
public ChannelFuture register(final ChannelPromise promise) {
ObjectUtil.checkNotNull(promise, "promise");
promise.channel().unsafe().register(this, promise);
return promise;
}
DefaultChannelPromise实际是一个Future对象,Netty对它进行了封装扩展。
绕了这么久,终于来到AbstractChannel的register。
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
// 忽略校验
...
// 关联eventLoop
AbstractChannel.this.eventLoop = eventLoop;
// 判断当前线程是否为NioEventLoop关联的线程
if (eventLoop.inEventLoop()) {
register0(promise);
} else {
try {
eventLoop.execute(new Runnable() {
public void run() {
register0(promise);
}
});
} catch (Throwable t) {
...
}
}
}
private void register0(ChannelPromise promise) {
try {
// 省略校验
...
boolean firstRegistration = neverRegistered;
doRegister();
neverRegistered = false;
registered = true;
// 这里执行前文添加的ChannelInitializer里面的方法
pipeline.invokeHandlerAddedIfNeeded();
// 修改当前promise状态为成功
safeSetSuccess(promise);
// 发布注册成功事件通知,将从header开始流转每一个ChannelInboundHandler处理事件
pipeline.fireChannelRegistered();
// 此时的channel其实还未成功激活,下面逻辑不会执行
if (isActive()) {
if (firstRegistration) {
// 向pipeline传播active事件
pipeline.fireChannelActive();
} else if (config().isAutoRead()) {
beginRead();
}
}
} catch (Throwable t) {
...
}
}
1.doRegister
这个的实现来自于AbstractNioChannel
protected void doRegister() throws Exception {
boolean selected = false;
for (;;) {
try {
// 这里主要注册一个什么都不感兴趣的channel,后续会调整
// 一个eventLoop对应一个selector
selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
return;
} catch (CancelledKeyException e) {
...
}
}
}
这一步主要是为了获取selectionKey 实例,后续通过interestOps(int ops)修改感兴趣的时间。
2.invokeHandlerAddedIfNeeded
进入invokeHandlerAddedIfNeeded方法
final void invokeHandlerAddedIfNeeded() {
assert channel.eventLoop().inEventLoop();
if (firstRegistration) {
firstRegistration = false;
callHandlerAddedForAllHandlers();
}
}
private void callHandlerAddedForAllHandlers() {
final PendingHandlerCallback pendingHandlerCallbackHead;
....
// 这里执行了pendingHandlerCallbackHead,之前将ChannelInitializer封装到里面
PendingHandlerCallback task = pendingHandlerCallbackHead;
while (task != null) {
task.execute();
task = task.next;
}
}
沿着调用链,最终执行了ChannelInitializer的handlerAdded
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
// 此时进入这里
if (ctx.channel().isRegistered()) {
if (initChannel(ctx)) {
removeState(ctx);
}
}
}
private boolean initChannel(ChannelHandlerContext ctx) throws Exception {
// 并发处理,避免线程执行过
if (initMap.add(ctx)) {
try {
// 这里执行ChannelInitializer 匿名方法的操作
initChannel((C) ctx.channel());
} catch (Throwable cause) {
...
} finally {
// 移除当前ChannelInitializer
ChannelPipeline pipeline = ctx.pipeline();
if (pipeline.context(this) != null) {
pipeline.remove(this);
}
}
return true;
}
return false;
}
这里为何要pipeline.remove(this)呢?
因为当前的上下文包裹的是一个ChannelInitializer ,ChannelInitializer是为解决ServerBootstrap不支持添加多个handler而诞生的,故而ChannelInitializer本身是没有用处的。
经过invokeHandlerAddedIfNeeded方法之后管道变成这样