1,Netty 是怎么创建服务端 Channel 的呢?
我们在使用 ServerBootstrap.bind(端口) 方法时, 最终调用其父类 AbstractBootstrap 中的 doBind 方法, 相关源码如下:
- private ChannelFuture doBind(final SocketAddress localAddress) {
- // 初始化和注册
- final ChannelFuture regFuture = initAndRegister();
- .....
我们继续跟进 initAndRegister() 这个方法, 发现是使用 channelFactory.newChannel() 完成 channel 的创建:
- final ChannelFuture initAndRegister() {
- Channel channel = null;
- try {
- channel = channelFactory.newChannel();
- init(channel);
- } catch (Throwable t) {......}
ChannelFactory 在实现类 ReflectiveChannelFactory 中的实现细节, 内部使用了反射的方式创建 Channel:
- public T newChannel() {
- try {
- return clazz.newInstance();
- } catch (Throwable t) {......}
- }
这里的 ChannelFactory 是通过 Bootstrap.channel(NioServerSocketChannel.class) 加入的:
- public B channel(Class<? extends C> channelClass) {
- if (channelClass == null) {
- throw new NullPointerException("channelClass");
- }
- return channelFactory(new ReflectiveChannelFactory<C>(channelClass));
- }
综上所述, Netty 就是调用 jdk 底层方法创建 NIO 的 channel, 也就是通过反射完成 NIO 的 channel 创建. 最后其包装成 Netty 自己的 Channel.
2, 初始化服务端 Channel 是怎么样的执行流程?
在创建了 Channel 之后就调用 AbstractBootstrap 的 init(channel) 抽象方法完成初始化:
abstract void init(Channel channel) throws Exception;
服务器端 ServerBootstrap 的 init 方法从源码来看主要完成工作为:
配置相关的 Options 和 Attribute.
通过 ChannelPipeline 添加相关逻辑处理器 ChannelHandler.
最后这些属性会传入 ServerBootstrapAcceptor 连接器, 通过 ServerBootstrapAcceptor 连接器完成相应的初始化.
- // We add this handler via the EventLoop as the user may have used a ChannelInitializer as handler.
- // In this case the initChannel(...) method will only be called after this method returns. Because
- // of this we need to ensure we add our handler in a delayed fashion so all the users handler are
- // placed in front of the ServerBootstrapAcceptor.
- ch.eventLoop().execute(new Runnable() {
- @Override
- public void run() {
- pipeline.addLast(new ServerBootstrapAcceptor(
- currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
- }
- });
3, 怎么注册 selector?
在 Java NIO 中注册通道 Channel 到多路复用器 Selector, 并说明关注点 SelectionKey.OP_ACCEPT, 监听 ACCEPT 事件通常我们会这样写:
serverSocket.register(selector, SelectionKey.OP_ACCEPT);
Netty 在底层将 Channel 注册到事件轮询器 selector 上就是基于此方法:
首先在初始化 Channel 后执行:
ChannelFuture regFuture = config().group().register(channel);
上面的代码实际是调用 AbstractChannel 的 register 方法, 完成 eventLoop 的绑定. 内部方法 register0() 中会调用 AbstractNioChannel 的 doRegister() 方法:
- protected void doRegister() throws Exception {
- boolean selected = false;
- for (;;) {
- try {
- selectionKey = javaChannel().register(eventLoop().selector, 0, this);
- return;
- } catch (CancelledKeyException e) {......}
- }
- }
这里其实就是调用 NIO SelectableChannel 的 register 方法.
从源码可以知道, 注册成功后这里会以此执行服务器 handler 中的回调方法: handlerAdded ,channelActive
4, 端口怎么绑定呢?
一切 OK 之后就会调用 AbstractChannel 中的 bind 方法, 这个方法又会调用 NioServerSocketChannel 的 doBind 方法, 从 doBind 方法可知是调用的原生 NIO 的 bind 做绑定:
- protected void doBind(SocketAddress localAddress) throws Exception {
- if (PlatformDependent.javaVersion()>= 7) {
- javaChannel().bind(localAddress, config.getBacklog());
- } else {
- javaChannel().socket().bind(localAddress, config.getBacklog());
- }
- }
绑定完成后会执行代码:
- if (!wasActive && isActive()) {
- invokeLater(new Runnable() {
- @Override
- public void run() {
- pipeline.fireChannelActive();
- }
- });
- }
这里会调用 DefaultChannelPipeline 中的内部类 HeadContext 的 channelActive 方法进行事件传播:
- @Override
- public void channelActive(ChannelHandlerContext ctx) throws Exception {
- ctx.fireChannelActive();
- readIfIsAutoRead();
- }
那么服务端到底是在哪里 accept 连接的呢?
通过上面的代码我们跟进 AbstractChannel 的 beginRead() 方法, 继而找到 AbstractNioChannel 的 doBeginRead() 方法:
- protected void doBeginRead() throws Exception {
- // Channel.read() or ChannelHandlerContext.read() was called
- final SelectionKey selectionKey = this.selectionKey;
- if (!selectionKey.isValid()) {
- return;
- }
- readPending = true;
- final int interestOps = selectionKey.interestOps();
- if ((interestOps & readInterestOp) == 0) {
- selectionKey.interestOps(interestOps | readInterestOp);
- }
- }
上面的代码就是 NIO 编程中常用的写法, 这里监听 ACCEPT 事件就是 NioServerSocketChannel 构造函数调用父类传入的 SelectionKey.OP_ACCEPT:
- public NioServerSocketChannel(ServerSocketChannel channel) {
- super(null, channel, SelectionKey.OP_ACCEPT);
- config = new NioServerSocketChannelConfig(this, javaChannel().socket());
- }
来源: https://www.cnblogs.com/monkjavaer/p/11312392.html