netty理论之源码分析① Bootstrap和ServerBootstrap

首先来复习一下nio的概念:

  从Java1.4开始, Java引入了non-blocking IO,简称NIO。

NIO 由以下几个核心部分组成:Channels,Buffers,Selectors

虽然Java NIO 中除此之外还有很多类和组件,但在我看来,Channel,Buffer 和 Selector 构成了核心的API。其它组件,如Pipe和FileLock,只不过是与三个核心组件共同使用的工具类。因此,在概述中我将集中在这三个组件上。其它组件会在单独的章节中讲到。NIO与传统socket最大的不同就是引入了Channel和多路复用selector的概念。传统的socket是基于stream的,它是单向的,有InputStream表示read和OutputStream表示写。而Channel是双工的,既支持读也支持写,channel的读/写都是面向Buffer。 NIO中引入的多路复用Selector机制(如果是linux系统,则应用的epoll事件通知机制)可使一个线程同时监听多个Channel上发生的事件。 虽然Java NIO相比于以往确实是一个大的突破,但是如果要真正上手进行开发,且想要开发出好的一个服务端网络程序,那么你得要花费一点功夫了,毕竟Java NIO只是提供了一大堆的API而已,对于一般的软件开发人员来说只能呵呵了。因此,社区中就涌现了很多基于Java NIO的网络应用框架,其中以Apache的Mina,以及Netty最为出名,从本篇开始我们将深入的分析一下Netty的内部实现细节 。

在分析源码之前,我们还是先看看Netty官方的样例代码,了解一下Netty一般是如何进行服务端及客户端开发的。

Netty服务端示例:

EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
    ServerBootstrap b = new ServerBootstrap(); // (2)
    b.group(bossGroup, workerGroup)  // (3)
     .channel(NioServerSocketChannel.class) // (4)
     .handler(new LoggingHandler())    // (5)
     .childHandler(new ChannelInitializer<SocketChannel>() { // (6)
         @Override
         public void initChannel(SocketChannel ch) throws Exception {
             ch.pipeline().addLast(new DiscardServerHandler());
         }
     })
     .option(ChannelOption.SO_BACKLOG, 128)          // (7)
     .childOption(ChannelOption.SO_KEEPALIVE, true); // (8)

     // Bind and start to accept incoming connections.
     ChannelFuture f = b.bind(port).sync(); // (9)

     // Wait until the server socket is closed.
     // In this example, this does not happen, but you can do that to gracefully
     // shut down your server.
     f.channel().closeFuture().sync();
} finally {
    workerGroup.shutdownGracefully();
    bossGroup.shutdownGracefully();
}

根据注释中的备注分析一波服务端的代码

1、 初始化用于Acceptor的主”线程池”以及用于I/O工作的从”线程池”; 
2、 初始化ServerBootstrap实例,此实例是netty服务端应用开发的入口,也是本篇介绍的重点, 下面我们会深入分析; 
3、通过ServerBootstrap的group方法,设置(1)中初始化的主从”线程池”; 
4、指定通道channel的类型,由于是服务端,故而是NioServerSocketChannel; 
5、设置ServerSocketChannel的处理器(此处不详述,后面的系列会进行深入分析) 
6、设置子通道也就是SocketChannel的处理器, 其内部是实际业务开发的”主战场”(此处不详述,后面的系列会进行深入分析) 
7、配置ServerSocketChannel的选项 
8、 配置子通道也就是SocketChannel的选项 
9、 绑定并侦听某个端口

接着,我们再看看客户端端是如何开发的:

Netty客户端示例:

public class TimeClient {
    public static void main(String[] args) throws Exception {
        String host = args[0];
        int port = Integer.parseInt(args[1]);
        EventLoopGroup workerGroup = new NioEventLoopGroup(); // (1)

        try {
            Bootstrap b = new Bootstrap(); // (2)
            b.group(workerGroup); // (3)
            b.channel(NioSocketChannel.class); // (4)
            b.option(ChannelOption.SO_KEEPALIVE, true); // (5)
            b.handler(new ChannelInitializer<SocketChannel>() { // (6)
                @Override
                public void initChannel(SocketChannel ch) throws Exception {
                    ch.pipeline().addLast(new TimeClientHandler());
                }
            });

            // Start the client.
            ChannelFuture f = b.connect(host, port).sync(); // (7)

            // Wait until the connection is closed.
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
        }
    }
}

根据注释中的备注分析一波客户端的代码:

1、 初始化用于连接及I/O工作的”线程池”; 
2、 初始化Bootstrap实例, 此实例是netty客户端应用开发的入口,也是本篇介绍的重点, 下面我们会深入分析; 
3、 通过Bootstrap的group方法,设置(1)中初始化的”线程池”; 
4、 指定通道channel的类型,由于是客户端,故而是NioSocketChannel; 
5、 设置SocketChannel的选项(此处不详述,后面的系列会进行深入分析); 
6、 设置SocketChannel的处理器, 其内部是实际业务开发的”主战场”(此处不详述,后面的系列会进行深入分析); 
7、 连接指定的服务地址;

在分析之前先来,相信大家都清楚了ServerBootstrap和Bootstrap的大致关系

1.如图AbstractBootstrap类是ServerBootstrap及Bootstrap的基类

扫描二维码关注公众号,回复: 2929616 查看本文章

2.ServerBootstrap绑定到指定端口来监听客户端连接请求,Bootstrap连接至远程服务端。并且ServerBootstrap包含两个EventLoopGroup,而Bootstrap只包含一个EventLoopGroup。ServerBootstrap包含两组通道,第一组包含一个ServerChannel,表示服务器绑定到本地端口的监听套接字;第二组包含用来处理客户端连接所创建的所有通道,每接受一个连接时便会创建一个通道,下图显示了ServerBootstrap的两个EventLoopGroup。

一、先从AbstractBootstrap讲起

我们先看一下AbstractBootstrap类的主要代码:

public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {

    volatile EventLoopGroup group;
    private volatile ChannelFactory<? extends C> channelFactory;
    private final Map<ChannelOption<?>, Object> options = new LinkedHashMap<ChannelOption<?>, Object>();
    private final Map<AttributeKey<?>, Object> attrs = new LinkedHashMap<AttributeKey<?>, Object>();
    private volatile ChannelHandler handler;


    public B group(EventLoopGroup group) {
        if (group == null) {
            throw new NullPointerException("group");
        }
        if (this.group != null) {
            throw new IllegalStateException("group set already");
        }
        this.group = group;
        return self();
    }

    private B self() {
        return (B) this;
    }

    public B channel(Class<? extends C> channelClass) {
        if (channelClass == null) {
            throw new NullPointerException("channelClass");
        }
        return channelFactory(new ReflectiveChannelFactory<C>(channelClass));
    }

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

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

    public B channelFactory(io.netty.channel.ChannelFactory<? extends C> channelFactory) {
        return channelFactory((ChannelFactory<C>) channelFactory);
    }

    public <T> B option(ChannelOption<T> option, T value) {
        if (option == null) {
            throw new NullPointerException("option");
        }
        if (value == null) {
            synchronized (options) {
                options.remove(option);
            }
        } else {
            synchronized (options) {
                options.put(option, value);
            }
        }
        return self();
    }

    public <T> B attr(AttributeKey<T> key, T value) {
        if (key == null) {
            throw new NullPointerException("key");
        }
        if (value == null) {
            synchronized (attrs) {
                attrs.remove(key);
            }
        } else {
            synchronized (attrs) {
                attrs.put(key, value);
            }
        }
        return self();
    }

    public B validate() {
        if (group == null) {
            throw new IllegalStateException("group not set");
        }
        if (channelFactory == null) {
            throw new IllegalStateException("channel or channelFactory not set");
        }
        return self();
    }

    public ChannelFuture bind(int inetPort) {
        return bind(new InetSocketAddress(inetPort));
    }

    public ChannelFuture bind(SocketAddress localAddress) {
        validate();
        if (localAddress == null) {
            throw new NullPointerException("localAddress");
        }
        return doBind(localAddress);
    }

    private ChannelFuture doBind(final SocketAddress localAddress) {
        final ChannelFuture regFuture = initAndRegister();
        final Channel channel = regFuture.channel();
        if (regFuture.cause() != null) {
            return regFuture;
        }

        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.
            final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
            regFuture.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    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;
        }
    }

    final ChannelFuture initAndRegister() {
        Channel channel = null;
        try {
            channel = channelFactory.newChannel();
            init(channel);
        } catch (Throwable t) {
            if (channel != null) {
                // channel can be null if newChannel crashed (eg SocketException("too many open files"))
                channel.unsafe().closeForcibly();
            }
            // as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
            return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
        }

        ChannelFuture regFuture = config().group().register(channel);
        if (regFuture.cause() != null) {
            if (channel.isRegistered()) {
                channel.close();
            } else {
                channel.unsafe().closeForcibly();
            }
        }

        return regFuture;
    }

    abstract void init(Channel channel) throws Exception;

    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.
        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());
                }
            }
        });
    }

    public B handler(ChannelHandler handler) {
        if (handler == null) {
            throw new NullPointerException("handler");
        }
        this.handler = handler;
        return self();
    }public abstract AbstractBootstrapConfig<B, C> config();

}

现在我们以示例代码为出发点,来详细分析一下引导类内部实现细节:

1、 首先看看服务端的b.group(bossGroup, workerGroup):

调用ServerBootstrap的group方法,设置react模式的主线程池 以及 IO 操作线程池,ServerBootstrap中的group代码如下:

public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
        super.group(parentGroup);
        if (childGroup == null) {
            throw new NullPointerException("childGroup");
        }
        if (this.childGroup != null) {
            throw new IllegalStateException("childGroup set already");
        }
        this.childGroup = childGroup;
        return this;
    }

在group方法中,会继续调用父类的group方法,而通过类继承图我们知道,super.group(parentGroup)其实调用的就是AbstractBootstrap的group方法。AbstractBootstrap中group代码如下:

public B group(EventLoopGroup group) {
    if (group == null) {
        throw new NullPointerException("group");
    }
    if (this.group != null) {
        throw new IllegalStateException("group set already");
    }
    this.group = group;
    return self();
}

通过以上分析,我们知道了AbstractBootstrap中定义了主线程池group的引用,而子线程池childGroup的引用是定义在ServerBootstrap中。

当我们查看客户端Bootstrap的group方法时,我们发现,其是直接调用的父类AbstractBoostrap的group方法。

2、示例代码中的 channel()方法

无论是服务端还是客户端,channel调用的都是基类的channel方法,其实现细节如下:

public B channel(Class<? extends C> channelClass) {
    if (channelClass == null) {
        throw new NullPointerException("channelClass");
    }
    return channelFactory(new ReflectiveChannelFactory<C>(channelClass));
}


=====================================================

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

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

3、option / handler / attr 方法

option: 设置通道的选项参数, 对于服务端而言就是ServerSocketChannel, 客户端而言就是SocketChannel;

handler: 设置主通道的处理器, 对于服务端而言就是ServerSocketChannel,也就是用来处理Acceptor的操作;对于客户端的SocketChannel,主要是用来处理 业务操作;

attr: 设置通道的属性;

option / handler / attr方法都定义在AbstractBootstrap中, 所以服务端和客户端的引导类方法调用都是调用的父类的对应方法。

4、childHandler / childOption / childAttr 方法(只有服务端ServerBootstrap才有child类型的方法)

对于服务端而言,有两种通道需要处理, 一种是ServerSocketChannel:用于处理用户连接的accept操作, 另一种是SocketChannel,表示对应客户端连接。而对于客户端,一般都只有一种channel,也就是SocketChannel。

因此以child开头的方法,都定义在ServerBootstrap中,表示处理或配置服务端接收到的对应客户端连接的SocketChannel通道。

childHandler / childOption / childAttr 在ServerBootstrap中的对应代码如下:

public ServerBootstrap childHandler(ChannelHandler childHandler) {
    if (childHandler == null) {
        throw new NullPointerException("childHandler");
    }
    this.childHandler = childHandler;
    return this;
}

=======================================================================

public <T> ServerBootstrap childOption(ChannelOption<T> childOption, T value) {
    if (childOption == null) {
        throw new NullPointerException("childOption");
    }
    if (value == null) {
        synchronized (childOptions) {
            childOptions.remove(childOption);
        }
    } else {
        synchronized (childOptions) {
            childOptions.put(childOption, value);
        }
    }
    return this;
}


===========================================================================


public <T> ServerBootstrap childAttr(AttributeKey<T> childKey, T value) {
    if (childKey == null) {
        throw new NullPointerException("childKey");
    }
    if (value == null) {
        childAttrs.remove(childKey);
    } else {
        childAttrs.put(childKey, value);
    }
    return this;
}

上面是引导类的属性配置都设置完毕了。

二、接下来介绍Bootstrap和ServerBootStrap(部分介绍和一重复)

Bootstrap是netty中用于创建Server、Client端代码的构造工具类,里面包括了启动Server、Client需要的配置信息等。下面用一段代码来初步了解下。

// 创建ServerBootstrap
ServerBootstrap bootstrap = new ServerBootstrap();
// 创建用户acceptor和dispatcher io event的io线程池
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
	// 设置server的channel类型为NioServerSocketChannel
    bootstrap.channel(NioServerSocketChannel.class)
            // 设置对应的io线程池
            .group(bossGroup, workerGroup)
            // 设置新建连接的处理器
            .childHandler(new ChannelInitializer<SocketChannel>() {
                protected void initChannel(SocketChannel ch) throws Exception {
                    // 对于新建的连接,在它的ChannelPipeline上增加一个EchoHandler
                    ch.pipeline().addLast(new EchoHandler());
                }
            });
    // 绑定到8090
    ChannelFuture bind = bootstrap.bind(8090);
    // netty中大多数操作都是异步的,所以上面的bind方法会立刻返回并返回一个Future, 需要sync阻塞等待bind成功
    bind.sync();
    // 一直阻塞当前线程知道server channel关闭
    bind.channel().closeFuture().sync();
} finally {
	// 关闭线程池
    bossGroup.shutdownGracefully().sync();
    workerGroup.shutdownGracefully().sync();
}

BootStrap源码分析

下图简单描述了一下BootStrap

主要的代码类为

  • io.netty.bootstrap.Bootstrap
  • io.netty.bootstrap.ServerBootstrap
  • io.netty.bootstrap.AbstractBootstrap
  • io.netty.bootstrap.AbstractBootstrapConfig
  • io.netty.bootstrap.ServerBootstrapConfig
  • io.netty.bootstrap.BootstrapConfig

AbstractBootstrap

AbstractBootstrap通过提供chain方法链提供方面的Channel配置方式。
这里要了解一种很多代码中用到的看上去不太好懂的Hierarchical Builder模式。(完整AbstractBootstrap代码如上)


public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
...
/**
     * The {@link EventLoopGroup} which is used to handle all the events for the to-be-created
     * {@link Channel}
     */
public B group(EventLoopGroup group) {
if (group == null) {
throw new NullPointerException("group");
}
if (this.group != null) {
throw new IllegalStateException("group set already");
}
this.group = group;
return self();
}
@SuppressWarnings("unchecked")
private B self() {
return (B) this;
}

这里的AbstractBootstrap<b extends="" abstractbootstrap
返回了B类型的对象,这样又可以通过其他方法返回B的串联起来,这些方法最后都调用了B self()返回this, 这个this的类型是子类型,这样子类就可以直接使用而不必强行转换父类型到子类型了。
这时ServerBootstrap继承AbstractBootstrap并将B设置为自己时,就可以方便的在AbstractBootstrap基础上增加配置方法了。


public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel> {
	public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
super.group(parentGroup);
if (childGroup == null) {
throw new NullPointerException("childGroup");
}
if (this.childGroup != null) {
throw new IllegalStateException("childGroup set already");
}
this.childGroup = childGroup;
return this;
}
...
}

这里的ServerBootstrap在AbstractBootstrap的基础上又添加了group(parentGroup, childGroup)的方法。所以这种写法很适合多级Builder。
当子类继承

AbstractBootstrapConfig

AbstratBootstrapConfig向外暴露AbstractBootstrap的配置。


public abstract class AbstractBootstrapConfig<B extends AbstractBootstrap<B, C>, C extends Channel> {
protected final B bootstrap;
protected AbstractBootstrapConfig(B bootstrap) {
this.bootstrap = ObjectUtil.checkNotNull(bootstrap, "bootstrap");
}
/**
     * Returns the configured local address or {@code null} if non is configured yet.
     */
public final SocketAddress localAddress() {
return bootstrap.localAddress();
}

AbstractBootstrapConfig提供基础的AbstractBootstrap拥有的配置,具体子类又可以提供其具体AbstractBootstrap的配置,
例如ServerBootstrapConfig中B为ServerBoostrap,就可以返回更多的ServerBootstrap中的方法例如childGroup等。


ublic final class ServerBootstrapConfig extends AbstractBootstrapConfig<ServerBootstrap, ServerChannel> {
ServerBootstrapConfig(ServerBootstrap bootstrap) {
super(bootstrap);
}
/**
     * Returns the configured {@link EventLoopGroup} which will be used for the child channels or {@code null}
     * if non is configured yet.
     */
@SuppressWarnings("deprecation")
public EventLoopGroup childGroup() {
return bootstrap.childGroup();
}
...

ServerBootstrap bind过程

通常在给ServerBootstrap配置好各种参数后的最后一步就是bind。
Server的bind将创建一个本地的ServerSocket绑定到对应端口上,并且配置接受到新的socket后的处理等。
下面看一下具体的bind过程。

AbstractBootstrap中


/**
     * Create a new {@link Channel} and bind it.
     */
public ChannelFuture bind(SocketAddress localAddress) {
validate();
if (localAddress == null) {
throw new NullPointerException("localAddress");
}
return doBind(localAddress);
}


=====================================================

private ChannelFuture doBind(final SocketAddress localAddress) {
final ChannelFuture regFuture = initAndRegister();
final Channel channel = regFuture.channel();
if (regFuture.cause() != null) {
return regFuture;
}
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.
final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
regFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
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;
}
}

initAndRegister

  • 负责通过ChannelFactory创建Channel

  • 初始化 init Channel

  • 注册Channel到EventLoopGroup上


final ChannelFuture initAndRegister() {
Channel channel = null;
try {
channel = channelFactory.newChannel();
init(channel);
} catch (Throwable t) {
if (channel != null) {
// channel can be null if newChannel crashed (eg SocketException("too many open files"))
channel.unsafe().closeForcibly();
// as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
}
// as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
return new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE).setFailure(t);
}
ChannelFuture regFuture = config().group().register(channel);
if (regFuture.cause() != null) {
if (channel.isRegistered()) {
channel.close();
} else {
channel.unsafe().closeForcibly();
}
}
// If we are here and the promise is not failed, it's one of the following cases:
// 1) If we attempted registration from the event loop, the registration has been completed at this point.
//    i.e. It's safe to attempt bind() or connect() now because the channel has been registered.
// 2) If we attempted registration from the other thread, the registration request has been successfully
//    added to the event loop's task queue for later execution.
//    i.e. It's safe to attempt bind() or connect() now:
//         because bind() or connect() will be executed *after* the scheduled registration task is executed
//         because register(), bind(), and connect() are all bound to the same thread.
return regFuture;
}

通过ServerBootstrap.channel(NioServerSocketChannel.class)这样配置的ServerBootstrap
使用的是ReflectiveChannelFactory, 通过对应的类的构造器反射创建Channel对象。

ServerBootstrap的init方法中将前面配置的Bootstrap的attr、option等设置到Channel上
然后给当前ServerChannel增加一个ChannelInitializer, initChannel会在Channel注册完成后调用,
这里会给Channel添加Bootstrap中配置的Handler,然后给继续在pipeline上添加一个ServerBootstrapAcceptor。
ServerBootstrapAcceptor就是ServerSocket接受到新建的socket连接的处理。
注意到这里给pipeline添加ServerBootstrapAcceptor放到的channel的eventloop中去执行,这样做的原因是


void init(Channel channel) throws Exception {
final Map<ChannelOption<?>, Object> options = options0();
synchronized (options) {
setChannelOptions(channel, options, logger);
}
final Map<AttributeKey<?>, Object> attrs = attrs0();
synchronized (attrs) {
for (Entry<AttributeKey<?>, Object> e: attrs.entrySet()) {
@SuppressWarnings("unchecked")
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;
synchronized (childOptions) {
currentChildOptions = childOptions.entrySet().toArray(newOptionArray(childOptions.size()));
}
synchronized (childAttrs) {
currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(childAttrs.size()));
}
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。
											ServerBootstrapAcceptor就是ServerSocket接受到新建的socket连接的处理。(
ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}
});
}
});
}

ServerBootstrapAcceptor
首先给接受到的Channel(child)添加配置的childHandler、设置ChannelOption、ChannelAttribute等。
然后注册到childGroup上,对应于上面示例代码中的workerGroup。


public void channelRead(ChannelHandlerContext ctx, Object msg) {
final Channel child = (Channel) msg;
child.pipeline().addLast(childHandler);
setChannelOptions(child, childOptions, logger);
for (Entry<AttributeKey<?>, Object> e: childAttrs) {
child.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());
}
try {
childGroup.register(child).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
forceClose(child, future.cause());
}
}
});
} catch (Throwable t) {
forceClose(child, t);
}

注册到EventLoopGruop上

	
ChannelFuture regFuture = config().group().register(channel);

NioEventLoopGroup继承于MultithreadEventLoopGroup,next()方法会round-robin的方式选出一个NioEventLoop,
然后设置Channel的eventLoop为这个NioEventLoop然后发出channelRegister事件等。@Override
public ChannelFuture register(Channel channel) {
return next().register(channel);
}

MultithreadEventLoopGroup


@Override
public ChannelFuture register(Channel channel) {
return next().register(channel);
}
	public EventExecutor next() {
return chooser.next();
}

chooser的作用是从EventExecutor中选出一个作为next的返回结果


public EventExecutorChooser newChooser(EventExecutor[] executors) {
if (isPowerOfTwo(executors.length)) {
return new PowerOfTwoEventExecutorChooser(executors);
} else {
return new GenericEventExecutorChooser(executors);
}
}

NioEventLoop继承于SingleThreadEventLoop


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

AbstractChannel
这里register中的处理是
设置当前Channel的eventLoop,fireChannelRegister事件,如果当前Channel是active状态并且是第一次注册则fireChannelActive事件


public final void register(EventLoop eventLoop, final ChannelPromise promise) {
if (eventLoop == null) {
throw new NullPointerException("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.this.eventLoop = eventLoop;
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);
}
}
}

initAndRegister完成后,会进行doBind0

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.
			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());
							}
					}
			});
	}

doBind0调用AbstractChannel的bind方法,然后调用pipeline.bind。
后面会讲到ChannelPipeline,ChannelPipeline中有一个特殊的ChannelHandler是HeadContext,作为pipelien的head节点。

public void bind(
ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise)
throws Exception {
unsafe.bind(localAddress, promise);
}

unsafe是一个接口,不同的io channel有不同的实现,
NioServerSocketChannel
可以看到java7以上使用jdk的ServerSocketChannel.bind方法,小于的版本得到对应的socket后进行bind

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

猜你喜欢

转载自blog.csdn.net/weixin_39666581/article/details/81152847
今日推荐