文章

2. 启动服务前ServerBootstrap类型如何初始化

2. 启动服务前ServerBootstrap类型如何初始化

启动服务前ServerBootstrap类型如何初始化

1
ServerBootstrap serverBootstrap = new ServerBootstrap();
1
Bootstrap bootstrap = new Bootstrap();

了解Bootstrap的建模

以下为简单的继承关系图,服务端与客户端的配置类均继承于AbstractBootstrap。

BootStrap

图2.1 Bootstrap类继承关系

类型说明
AbstractBootstrap抽象配置类,用于简化Netty中Channel的启动过程。
ServerBootstrap服务端配置类,用于简化服务端Channel的启动流程。
Bootstrap客户端配置类,用于简化客户端Channel的启动流程。

ServerBootstrap构造器的初始化调用链

1
ServerBootstrap serverBootstrap = new ServerBootstrap();

根据Java基础的构造器知识,在每个构造器的第一行都会有个super()方法来调用父类的构造器,当前这个super方法我们可以省略,但是Java编译器底层还是会为我们默认加上这么一行super()代码来调用父类构造器。

父类AbstractBootstrap构造器的初始化

1
2
3
AbstractBootstrap() {
    // Disallow extending from a different package.
}

父类构造器这里并没有执行逻辑。随后开始类变量的初始化。

在ServerBootstrap和Bootstrap均存在类变量config,用于暴露bootstrap的配置。

1
2
3
4
// ServerBootstrap
private final ServerBootstrapConfig ServerBootstrapConfig config = new ServerBootstrapConfig(this);
// Bootstrap
private final BootstrapConfig config = new BootstrapConfig(this);

ServerBootstrapConfig和BootstrapConfig的构造器均会调用父类构造器AbstractBootstrapConfig(B bootstrap),简单地判断非空之后赋值给bootstrap。

1
2
3
protected AbstractBootstrapConfig(B bootstrap) {
    this.bootstrap = ObjectUtil.checkNotNull(bootstrap, "bootstrap");
}

此处先跳过NioEventLoopGroup的初始化,需要明白的是这里创建了两个线程组。

Bootstrap的参数设置

EventLoopGroup

1
2
3
4
5
6
7
8
public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
    super.group(parentGroup);
    if (this.childGroup != null) {
        throw new IllegalStateException("childGroup set already");
    }
    this.childGroup = ObjectUtil.checkNotNull(childGroup, "childGroup");
    return this;
}

ServerBootStrap这里会调用父类的group(EventLoopGroup group)方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
public B group(EventLoopGroup group) {
    ObjectUtil.checkNotNull(group, "group");
    if (this.group != null) {
        throw new IllegalStateException("group set already");
    }
    this.group = group;
    return self();
}

@SuppressWarnings("unchecked")
private B self() {
    return (B) this;
}

父类简单地检查非空后将parentGroup赋值给groupchildGroup赋值给ServerBootstrapchildGroup。而客户端Bootstrap.group方法直接调用父类的group方法。最后返回this不断进行build添加配置。

Channel

服务端与客户端的channel方法均来源于AbstractBootstrap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public B channel(Class<? extends C> channelClass) {
    return channelFactory(new ReflectiveChannelFactory<C>(
        ObjectUtil.checkNotNull(channelClass, "channelClass")
    ));
}

@Deprecated
public B channelFactory(ChannelFactory<? extends C> channelFactory) {
    ObjectUtil.checkNotNull(channelFactory, "channelFactory");
    if (this.channelFactory != null) {
        throw new IllegalStateException("channelFactory set already");
    }

    this.channelFactory = channelFactory;
    return self();
}

@SuppressWarnings({ "unchecked", "deprecation" })
public B channelFactory(io.netty.channel.ChannelFactory<? extends C> channelFactory) {
    return channelFactory((ChannelFactory<C>) channelFactory);
}

该方法的主要逻辑是使用反射创建Channel的实例。

首先检查传入的channelClass是否为空,通过ObjectUtil.checkNotNull进行非空验证。接着,它使用ReflectiveChannelFactorychannelClass包装为工厂类,并将其传递给channelFactory()方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class ReflectiveChannelFactory<T extends Channel> implements ChannelFactory<T> {

    private final Constructor<? extends T> constructor;

    public ReflectiveChannelFactory(Class<? extends T> clazz) {
        ObjectUtil.checkNotNull(clazz, "clazz");
        try {
            this.constructor = clazz.getConstructor();
        } catch (NoSuchMethodException e) {
            throw new IllegalArgumentException("Class " + StringUtil.simpleClassName(clazz) +
                    " does not have a public non-arg constructor", e);
        }
    }

    @Override
    public T newChannel() {
        try {
            return constructor.newInstance();
        } catch (Throwable t) {
            throw new ChannelException("Unable to create Channel from class " + constructor.getDeclaringClass(), t);
        }
    }

    @Override
    public String toString() {
        return StringUtil.simpleClassName(ReflectiveChannelFactory.class) +
                '(' + StringUtil.simpleClassName(constructor.getDeclaringClass()) + ".class)";
    }
}

Option

在设置完Channel后服务端调用了optionchildOption两个方法来分别设置bossGroupworkerGroup的参数。

Handler

同样简单地初始化了Handler属性。

Bind

绑定到指定端口。

1
ChannelFuture channelFuture = serverBootstrap.bind(10009).sync();

往下走看AbstractBootstrap.bind的逻辑。

1
2
3
4
public ChannelFuture bind(int inetPort) {
    // 创建一个绑定到指定端口的SocketAddress,并调用bind(SocketAddress)方法
    return bind(new InetSocketAddress(inetPort));
}

创建Socket对象

1
2
3
4
5
public ChannelFuture bind(SocketAddress localAddress) {
    // 验证必要参数是否已经设置,如EventLoopGroup和ChannelFactory
    validate();
    return doBind(ObjectUtil.checkNotNull(localAddress, "localAddress"));
}

validate()方法中简单地进行非空检查。两种Bootstrap具有不同的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
// ServerBootstrap.java
@Override
public ServerBootstrap validate() {
    super.validate();
    if (childHandler == null) {
        throw new IllegalStateException("childHandler not set");
    }
    if (childGroup == null) {
        logger.warn("childGroup is not set. Using parentGroup instead.");
        childGroup = config.group();
    }
    return this;
}
1
2
3
4
5
6
7
8
9
// Bootstrap.java
@Override
public Bootstrap validate() {
    super.validate();
    if (config.handler() == null) {
        throw new IllegalStateException("handler not set");
    }
    return this;
}

在doBind方法中执行绑定前的工作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
private ChannelFuture doBind(final SocketAddress localAddress) {
    // 初始化并注册Channel,返回一个注册的ChannelFuture
    final ChannelFuture regFuture = initAndRegister();
    final Channel channel = regFuture.channel();

    // 如果注册时发生错误,直接返回错误的结果
    if (regFuture.cause() != null) {
        return regFuture;
    }

    // 如果注册已经完成且成功,创建一个ChannelPromise
    if (regFuture.isDone()) {
        // At this point we know that the registration was complete and successful.
        ChannelPromise promise = channel.newPromise();
        // 进行实际的绑定操作
        doBind0(regFuture, channel, localAddress, promise);
        return promise;
    } else {
        // Registration future is almost always fulfilled already, but just in case it's not.
        // 如果注册还未完成,创建PendingRegistrationPromise并添加监听器
        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) {
                    // Registration on the EventLoop failed so fail the ChannelPromise directly to not cause an
                    // IllegalStateException once we try to access the EventLoop of the Channel.
                    promise.setFailure(cause);
                } else {
                    // Registration was successful, so set the correct executor to use.
                    // See https://github.com/netty/netty/issues/2586
                    // 注册成功后,执行绑定操作
                    promise.registered();

                    doBind0(regFuture, channel, localAddress, promise);
                }
            }
        });
        return promise;
    }
}

完成创建等操作后在doBind0中交给eventloop执行实际的绑定操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private static void doBind0(
    final ChannelFuture regFuture, final Channel channel,
    final SocketAddress localAddress, final ChannelPromise promise) {

    // This method is invoked before channelRegistered() is triggered.  Give user handlers a chance to set up
    // the pipeline in its channelRegistered() implementation.
    // 将实际的绑定操作放入到EventLoop的执行队列中,避免阻塞主线程
    channel.eventLoop().execute(new Runnable() {
        @Override
        public void run() {
            if (regFuture.isSuccess()) {
                channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
            } else {
                promise.setFailure(regFuture.cause());
            }
        }
    });
}

至此就完成了端口绑定,接下来深入理解其中调用的方法。

initAndRegister

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
final ChannelFuture initAndRegister() {
    Channel channel = null;
    try {
        // 创建Channel
        channel = channelFactory.newChannel();
        init(channel);
    } catch (Throwable t) {
		// 省略报错
    }
    
    // 注册一个新的Channel到EventLoopGroup中,并返回一个ChannelFuture对象
    ChannelFuture regFuture = config().group().register(channel);
	// 省略报错

    return regFuture;
}

此处的channelFactory来源于BootStrap所设置的ReflectiveChannelFactory。

1
2
3
4
5
6
7
8
@Override
public T newChannel() {
    try { 
        return clazz.newInstance();
    } catch (Throwable t) {
        throw new ChannelException("Unable to create Channel from class " + clazz, t);
    }
}

通过反射来创建NioServerSocketChannel对象。

1
2
3
public NioServerSocketChannel() {
    this(DEFAULT_SELECTOR_PROVIDER);
}

该无参构造器调用了另一个有参构造器,先来看看其中的常量DEFAULT_SELECTOR_PROVIDER。

1
private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();

此处初始化了一个SelectorProvider对象,定义了创建 Selector、ServerSocketChannel、SocketChannel 等方法,并在不同平台下提供不同的实现

1
2
3
4
5
6
7
public NioServerSocketChannel(SelectorProvider provider) {
    this(provider, null);
}

public NioServerSocketChannel(SelectorProvider provider, InternetProtocolFamily family) {
    this(newChannel(provider, family));
}

继续看newChannel方法

1
2
3
4
5
6
7
8
9
private static ServerSocketChannel newChannel(SelectorProvider provider, InternetProtocolFamily family) {
    try {
        ServerSocketChannel channel =
            SelectorProviderUtil.newChannel(OPEN_SERVER_SOCKET_CHANNEL_WITH_FAMILY, provider, family);
        return channel == null ? provider.openServerSocketChannel() : channel;
    } catch (IOException e) {
        throw new ChannelException("Failed to open a socket.", e);
    }
}

使用SelectorProviderUtil来创建Channel,失败的话使用provider创建ServerSocketChannel。

// TODO:SelectorProviderUtil.newChannel

最后进入到

1
2
3
4
5
6
public NioServerSocketChannel(ServerSocketChannel channel) {
    super(null, channel, SelectionKey.OP_ACCEPT);
    // 调用一堆super来得到channel,实际就是参数中的channel
    // 使用channel初始化config
    config = new NioServerSocketChannelConfig(this, javaChannel().socket());
}
1
2
3
protected AbstractNioMessageChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
    super(parent, ch, readInterestOp);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
    super(parent);
    // 保存channel
    this.ch = ch;
    // 对应的事件
    this.readInterestOp = readInterestOp;
    try {
        // 设置为非阻塞
        ch.configureBlocking(false);
    } catch (IOException e) {
        try {
            ch.close();
        } catch (IOException e2) {
            logger.warn(
                "Failed to close a partially initialized socket.", e2);
        }

        throw new ChannelException("Failed to enter non-blocking mode.", e);
    }
}

this.ch = ch;绑定jdk底层的ServerSocketChannel, 至此,jdk的channel和netty定义的channel是组合关系,netty的channel中有个jdk的channel的成员变量,而这个成员变量就定义在AbstractNioChannel这个类当中

1
2
3
4
5
6
7
protected AbstractChannel(Channel parent) {
    this.parent = parent;
    // 创建唯一ID
    id = newId();
    unsafe = newUnsafe();
    pipeline = newChannelPipeline();
}

在顶层父类中初始化了两个属性unsafe,和pipeline,目前只需要知道这两个属性是在这里初始化。

init

接着看initAndRegister方法中的调用的init方法。服务端与客户端均重写了该方法,先从服务端开始。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
void init(Channel channel) {
    // 获取的用户定义的选项和属性
    setChannelOptions(channel, newOptionsArray(), logger);
    setAttributes(channel, newAttributesArray());
    // 获取channel的pipeline,这是一个处理入站和出站数据的处理器链
    ChannelPipeline p = channel.pipeline();

    // 获取用于配置的变量
    final EventLoopGroup currentChildGroup = childGroup;
    final ChannelHandler currentChildHandler = childHandler;
    final Entry<ChannelOption<?>, Object>[] currentChildOptions = newOptionsArray(childOptions);
    final Entry<AttributeKey<?>, Object>[] currentChildAttrs = newAttributesArray(childAttrs);
    final Collection<ChannelInitializerExtension> extensions = getInitializerExtensions();

    p.addLast(new ChannelInitializer<Channel>() {
        // 初始化channel
        @Override
        public void initChannel(final Channel ch) {
            final ChannelPipeline pipeline = ch.pipeline();
            ChannelHandler handler = config.handler();
            if (handler != null) {
                pipeline.addLast(handler);
            }
            // 添加 ServerBootstrapAcceptor
            // ServerBootstrapAcceptor负责处理已接受的通道,设置它们的选项、属性,并将它们注册到子事件循环组。
            ch.eventLoop().execute(new Runnable() {
                @Override
                public void run() {
                    pipeline.addLast(new ServerBootstrapAcceptor(
                        ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs,
                        extensions));
                }
            });
        }
    });
    if (!extensions.isEmpty() && channel instanceof ServerChannel) {
        ServerChannel serverChannel = (ServerChannel) channel;
        for (ChannelInitializerExtension extension : extensions) {
            try {
                extension.postInitializeServerListenerChannel(serverChannel);
            } catch (Exception e) {
                logger.warn("Exception thrown from postInitializeServerListenerChannel", e);
            }
        }
    }
}

注册channel

接着看initAndRegister方法中的调用的config().group().register(channel)方法。服务端与客户端均重写了该方法,先从服务端开始。

1
2
3
4
@Override
public final ServerBootstrapConfig config() {
    return config;
}

这段代码意思是返回在之前提到过的对应于每个BootstrapConfig。

再进到AbstractBootstrapConfig#group方法:

1
2
3
public final EventLoopGroup group() {
    return bootstrap.group();
}

调用了AbstractBootstrap#group(),也就是返回了ServerBootstrap的bossGroup。由于创建EventLoopGroup是使用NioEventLoopGroup,最后的注册也是父类MultithreadEventLoopGroup的register方法。

最后进到MultithreadEventLoopGroup#register(io.netty.channel.Channel)方法:

1
2
3
public ChannelFuture register(Channel channel) {
    return next().register(channel);
}

此处的next()的作用是从EventLoopGroup中选出一个EventLoop实例,也就是从线程组中选出一个线程。

继续进入到父类SingleThreadEventLoop#register(io.netty.channel.Channel)方法:

1
2
3
public ChannelFuture register(Channel channel) {
    return register(new DefaultChannelPromise(channel, this));
}

暂时先跳过DefaultChannelPromise的部分,继续看SingleThreadEventLoop#register(io.netty.channel.ChannelPromise):

1
2
3
4
5
public ChannelFuture register(final ChannelPromise promise) {
    ObjectUtil.checkNotNull(promise, "promise");
    promise.channel().unsafe().register(this, promise);
    return promise;
}

这行代码调用 promise 对象的 channel 方法获取关联的 Channel 对象,然后通过 unsafe 方法获取 Channel 的内部 Unsafe 实现,最后调用 register 方法将当前的 SingleThreadEventLoop 实例和 promise 注册到 Channel 中。此处的unsafe就是AbstractChannel#AbstractChannel(io.netty.channel.Channel)中所创建的unsafe。

// TODO:unsafe创建流程。

继续深入AbstractChannel.AbstractUnsafe#register(EventLoop eventLoop, final ChannelPromise promise):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
    // 参数检查
    ObjectUtil.checkNotNull(eventLoop, "eventLoop");
    if (isRegistered()) {
        promise.setFailure(new IllegalStateException("registered to an event loop already"));
        return;
    }
    if (!isCompatible(eventLoop)) {
        promise.setFailure(
            new IllegalStateException("incompatible event loop type: " + eventLoop.getClass().getName()));
        return;
    }

    // 明确地指定了要设置的是 AbstractChannel 实例的 eventLoop 属性,而不是 AbstractUnsafe 实例的属性。
    AbstractChannel.this.eventLoop = eventLoop;

    // 检查当前线程是否在 eventLoop 中运行,如果是,则直接调用 register0 方法进行注册:
    // 如果当前线程不在 eventLoop 中运行,则通过 eventLoop.execute 提交一个任务到 eventLoop 中执行 register0 方法:
    if (eventLoop.inEventLoop()) {
        register0(promise);
    } else {
        try {
            // 线程启动
            eventLoop.execute(new Runnable() {
                @Override
                public void run() {
                    register0(promise);
                }
            });
        } catch (Throwable t) {
            logger.warn(
                "Force-closing a channel whose registration task was not accepted by an event loop: {}",
                AbstractChannel.this, t);
            closeForcibly();
            closeFuture.setClosed();
            safeSetFailure(promise, t);
        }
    }
}

注意:

在 AbstractChannel 类中,register 方法是 AbstractUnsafe 的一个方法,而 AbstractUnsafe 是 AbstractChannel 的一个内部类。因此,this 关键字在 AbstractUnsafe 中指的是 AbstractUnsafe 的实例,而不是 AbstractChannel 的实例。

为了明确地引用外部类 AbstractChannel 的实例,使用 AbstractChannel.this。这确保了 eventLoop 属性被正确地设置为 AbstractChannel 实例的 eventLoop 属性,而不是 AbstractUnsafe 实例的属性。

继续进到AbstractChannel.AbstractUnsafe#register0(ChannelPromise promise):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
private void register0(ChannelPromise promise) {
    try {
        // check if the channel is still open as it could be closed in the mean time when the register
        // call was outside of the eventLoop
        // 参数检查
        if (!promise.setUncancellable() || !ensureOpen(promise)) {
            return;
        }
        boolean firstRegistration = neverRegistered;
        // 做实际的注册
        doRegister();
        // 更新状态
        neverRegistered = false;
        registered = true;

        // Ensure we call handlerAdded(...) before we actually notify the promise. This is needed as the
        // user may already fire events through the pipeline in the ChannelFutureListener.
        // 调用 pipeline.invokeHandlerAddedIfNeeded 确保在通知 promise 之前调用 handlerAdded 方法
        // 这是为了防止用户在 ChannelFutureListener 中触发事件时出现问题
        pipeline.invokeHandlerAddedIfNeeded();

        // 将 promise 设置为成功状态,并触发 pipeline.fireChannelRegistered 事件,通知管道已经注册:
        safeSetSuccess(promise);
        pipeline.fireChannelRegistered();
        // Only fire a channelActive if the channel has never been registered. This prevents firing
        // multiple channel actives if the channel is deregistered and re-registered.
        // 如果 Channel 是活跃的,并且这是第一次注册,则触发 pipeline.fireChannelActive 事件。
        // 如果 Channel 之前已经注册过,并且 config().isAutoRead() 返回 true,则调用 beginRead 方法开始读取数据:
        if (isActive()) {
            if (firstRegistration) {
                pipeline.fireChannelActive();
            } else if (config().isAutoRead()) {
                // This channel was registered before and autoRead() is set. This means we need to begin read
                // again so that we process inbound data.
                //
                // See https://github.com/netty/netty/issues/4805
                beginRead();
            }
        }
    } catch (Throwable t) {
        // Close the channel directly to avoid FD leak.
        closeForcibly();
        closeFuture.setClosed();
        safeSetFailure(promise, t);
    }
}

重点关注doRegister方法。进入到io.netty.channel.nio.AbstractNioChannel#doRegister():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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;
            }
        }
    }
}

方法中使用无限循环尝试组测Channel。首先看javaChannel方法。

1
2
3
4
5
6
7
8
// io.netty.channel.socket.nio.NioServerSocketChannel#javaChannel
protected ServerSocketChannel javaChannel() {
    return (ServerSocketChannel) super.javaChannel();
}
// io.netty.channel.nio.AbstractNioChannel#javaChannel
protected SelectableChannel javaChannel() {
    return ch;
}

实际上会返回的是AbstractNioChannel.ch,也就是jdk的ServerSocketChannel。eventLoop().unwrappedSelector(),是获得每一个eventLoop绑定的唯一的selector,0代表这次只是注册, 并不监听任何事件,this是代表将自身(NioEventLoopChannel)作为属性绑定在返回的selectionKey当中, 这个selectionKey就是与每个channel绑定的jdk底层的SelectionKey对象。

接着看jdk底层的java.nio.channels.spi.AbstractSelectableChannel#register:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public final SelectionKey register(Selector sel, int ops,
                                   Object att)
    throws ClosedChannelException
{
    synchronized (regLock) {
        if (!isOpen())
            throw new ClosedChannelException();
        if ((ops & ~validOps()) != 0)
            throw new IllegalArgumentException();
        if (blocking)
            throw new IllegalBlockingModeException();
        // 方法通过调用 findKey 方法检查当前通道是否已经注册到指定的 Selector 中
        SelectionKey k = findKey(sel);
        // 如果已经注册,则更新其兴趣操作集(interestOps)并附加新的附件(att)
        if (k != null) {
            k.interestOps(ops);
            k.attach(att);
        }
        // 如果当前通道尚未注册到指定的 Selector 中,通过调用 AbstractSelector 的 register 方法将通道注册到 Selector 中,并将返回的 SelectionKey 添加到当前通道的键集合中
        if (k == null) {
            // New registration
            synchronized (keyLock) {
                if (!isOpen())
                    throw new ClosedChannelException();
                k = ((AbstractSelector)sel).register(this, ops, att);
                addKey(k);
            }
        }
        return k;
    }
}

doBind0

在运行完initAndRegister()方法后,完成注册Channel。接着深入doBind0(regFuture, channel, localAddress, promise)方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private static void doBind0(
    final ChannelFuture regFuture, final Channel channel,
    final SocketAddress localAddress, final ChannelPromise promise) {

    // This method is invoked before channelRegistered() is triggered.  Give user handlers a chance to set up
    // the pipeline in its channelRegistered() implementation.
    // 将实际的绑定操作放入到EventLoop的执行队列中,避免阻塞主线程
    channel.eventLoop().execute(new Runnable() {
        @Override
        public void run() {
            if (regFuture.isSuccess()) {
                // 绑定端口
                channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
            } else {
                promise.setFailure(regFuture.cause());
            }
        }
    });
}

实际是使用channel来进行绑定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// io.netty.channel.AbstractChannel#bind(java.net.SocketAddress, io.netty.channel.ChannelPromise)
public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
    return pipeline.bind(localAddress, promise);
}
// io.netty.channel.DefaultChannelPipeline#bind(java.net.SocketAddress, io.netty.channel.ChannelPromise)
public final ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
    return tail.bind(localAddress, promise);
}
// io.netty.channel.AbstractChannelHandlerContext#bind(java.net.SocketAddress, io.netty.channel.ChannelPromise)
public ChannelFuture bind(final SocketAddress localAddress, final ChannelPromise promise) {
    ObjectUtil.checkNotNull(localAddress, "localAddress");
    if (isNotValidPromise(promise, false)) {
        // cancelled
        return promise;
    }

    // 查找下一个出站处理器上下文,该上下文具有 MASK_BIND 掩码
    final AbstractChannelHandlerContext next = findContextOutbound(MASK_BIND);
    // 获取该上下文的执行器(EventExecutor),并检查当前线程是否在执行器的事件循环中。
    // 如果是,则直接调用 next.invokeBind 方法执行绑定操作
    EventExecutor executor = next.executor();
    if (executor.inEventLoop()) {
        next.invokeBind(localAddress, promise);
        // 如果当前线程不在执行器的事件循环中,则通过 safeExecute 方法将绑定操作提交给执行器执行
    } else {
        safeExecute(executor, new Runnable() {
            @Override
            public void run() {
                next.invokeBind(localAddress, promise);
            }
        }, promise, null, false);
    }
    return promise;
}

invokeBind的调用链在此省略,会进入到AbstractChannel.AbstractUnsafe#bind(final SocketAddress localAddress, final ChannelPromise promise):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public final void bind(final SocketAddress localAddress, final ChannelPromise promise) {
    assertEventLoop();

    if (!promise.setUncancellable() || !ensureOpen(promise)) {
        return;
    }

    // See: https://github.com/netty/netty/issues/576
    if (Boolean.TRUE.equals(config().getOption(ChannelOption.SO_BROADCAST)) &&
        localAddress instanceof InetSocketAddress &&
        !((InetSocketAddress) localAddress).getAddress().isAnyLocalAddress() &&
        !PlatformDependent.isWindows() && !PlatformDependent.maybeSuperUser()) {
        // Warn a user about the fact that a non-root user can't receive a
        // broadcast packet on *nix if the socket is bound on non-wildcard address.
        logger.warn(
            "A non-root user can't receive a broadcast packet if the socket " +
            "is not bound to a wildcard address; binding to a non-wildcard " +
            "address (" + localAddress + ") anyway as requested.");
    }

    boolean wasActive = isActive();
    try {
        // 执行实际的绑定操作
        doBind(localAddress);
    } catch (Throwable t) {
        safeSetFailure(promise, t);
        closeIfClosed();
        return;
    }

    // 如果 Channel 在绑定后变为活跃状态,并且之前不是活跃的,则通过 invokeLater 方法触发 pipeline.fireChannelActive 事件,通知管道 Channel 已经活跃
    if (!wasActive && isActive()) {
        invokeLater(new Runnable() {
            @Override
            public void run() {
                pipeline.fireChannelActive();
            }
        });
    }

    safeSetSuccess(promise);
}

最后进入NioServerSocketChannel#doBind(SocketAddress localAddress):

1
2
3
4
5
6
7
protected void doBind(SocketAddress localAddress) throws Exception {
    if (PlatformDependent.javaVersion() >= 7) {
        javaChannel().bind(localAddress, config.getBacklog());
    } else {
        javaChannel().socket().bind(localAddress, config.getBacklog());
    }
}

此处javaChannel()返回的是jdk的ServerSocketChannel,所调用的bind方法也就是jdk底层的端口绑定逻辑。

最后回到.NettyServer#main

1
ChannelFuture channelFuture = serverBootstrap.bind(10009).sync();

最后调用了sync方法等待ChannelFuture返回结果。

本文由作者按照 CC BY 4.0 进行授权