Netty源码剖析之三:通过ServerBootstrap分析服务端启动流程

ServerBootstrapNetty中负责引导启动服务端程序,下面给出一个服务端启动的例子:

	EventLoopGroup bossGroup = new NioEventLoopGroup(); //bossGroup负责处理TCP/IP连接的
	EventLoopGroup workerGroup = new NioEventLoopGroup(); //workerGroup是负责处理Channel(通道)的I/O事件
 	ServerBootstrap sb = new ServerBootstrap();
    sb.group(bossGroup, workerGroup)
            .channel(NioServerSocketChannel.class)
            .childOption(ChannelOption.SO_KEEPALIVE, true) //保持长连接
            .childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel sh) throws Exception {
                    sh.pipeline()
                            .addLast(new LengthFieldBasedFrameDecoder(1024, 0, 4, 0, 4))
                            .addLast(new LengthFieldPrepender(4, false))
                            .addLast(new ServerHandler()); // 业务handler
                }
            });
    //绑定监听端口,调用sync同步阻塞方法等待绑定操作完
    ChannelFuture future = sb.bind(8081).sync();
    if (future.isSuccess()) {
        System.out.println("服务端启动成功");
    } else {
        System.out.println("服务端启动失败");
        future.cause().printStackTrace();
        bossGroup.shutdownGracefully(); //关闭线程组
        workerGroup.shutdownGracefully();
    }
    //成功绑定到端口之后,给channel增加一个管道关闭的监听器并同步阻塞,直到channel关闭,线程才会往下执行,结束进程。
    future.channel().closeFuture().sync();

1. ServerBootstrap类图

在这里插入图片描述

2. ServerBootstrap成员变量

public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
	// 主线程池
	volatile EventLoopGroup group; 
	// 负责创建channel的工厂类,服务端为NioServerSocketChannel,客户端为NioSocketChannel
	private volatile ChannelFactory<? extends C> channelFactory;
	private volatile SocketAddress localAddress;
	// socket及其它的一些属性设置
	private final Map<ChannelOption<?>, Object> options = new LinkedHashMap<ChannelOption<?>, Object>();
	// 附加属性设置
	private final Map<AttributeKey<?>, Object> attrs = new LinkedHashMap<AttributeKey<?>, Object>();
	// handler业务逻辑处理类
	private volatile ChannelHandler handler;
}
public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel> {
    private final Map<ChannelOption<?>, Object> childOptions = new ConcurrentHashMap<ChannelOption<?>, Object>();
    private final Map<AttributeKey<?>, Object> childAttrs = new ConcurrentHashMap<AttributeKey<?>, Object>();
    private final ServerBootstrapConfig config = new ServerBootstrapConfig(this);
    // 工作线程组
    private volatile EventLoopGroup childGroup;
    // 客户端连接时会触发执行
    private volatile ChannelHandler childHandler;
}

3. 服务端绑定逻辑AbstractBootstrap.bind()

  1. Netty服务端何时注册SelectionKey.OP_ACCEPT ?
  2. 主线程在哪里获取TCP请求 ,即执行selector.select()方法?

带着疑问,进入到AbstractBootstrap.bind()绑定方法

public ChannelFuture bind(int inetPort) {
    return bind(new InetSocketAddress(inetPort));
}
public ChannelFuture bind(SocketAddress localAddress) {
    validate(); // 验证
    return doBind(ObjectUtil.checkNotNull(localAddress, "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()) {
        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 {
                Throwable cause = future.cause();
                if (cause != null) {
                    promise.setFailure(cause);
                } else {
                    promise.registered();
                    doBind0(regFuture, channel, localAddress, promise);
                }
            }
        });
        return promise;
    }
}
3.1 AbstractBootstrap.initAndRegister()

大概流程:

  1. 实例化NioServerSocketChannel对象,创建服务端的Java Nio Channel、设置通道非阻塞,初始化字段pipelineunsafe等。
  2. init()方法,往ChannelPipeLine链表中中添加一个ChannelInitializer类型的事件处理。
  3. register(channel),将NioServerSocketChannel绑定主线程池的一个NioEventLoop线程,
    给Nio Channel感兴趣的事件0,并绑定当前NioServerSocketChannel对象给SelectedKey的attach,添加ServerBootstrapAcceptorpipeline中。
  4. doBind0()绑定地址和端口,当通道注册工作完成后绑定地址和端口,同时向通道中注册SelectionKey.OP_ACCEPT事件。
final ChannelFuture initAndRegister() {
    Channel channel = null;
    try {
        channel = channelFactory.newChannel(); // 实例化NioServerSocketChannel对象
        init(channel);
    } catch (Throwable t) {
    	// 异常返回
        if (channel != null) {
            channel.unsafe().closeForcibly();
            return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
        }
        return new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE).setFailure(t);
    }
    // 注册
    ChannelFuture regFuture = config().group().register(channel);
    // 注册失败,关闭Nio通道
    if (regFuture.cause() != null) {
        if (channel.isRegistered()) {
            channel.close();
        } else {
            channel.unsafe().closeForcibly();
        }
    }
    return regFuture;
}
3.1.1 NioServerSocketChannel对象实例化

大概流程:

  1. 创建NIO原生的Channel通道。
  2. 初始化变量AbstractNioChannel.readInterestOp = SelectionKey.OP_ACCEPT
  3. 设置通道非阻塞。
  4. 初始化变量AbstractChannel.unsafe = new NioMessageUnsafe()
  5. 初始化变量AbstractChannel.pipeline = new DefaultChannelPipeline(this)
// 多路复用选择器提供者SelectorProvider,用来创建多路复用选择器Selector
private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();
// 创建Java Nio Channel
private static ServerSocketChannel newSocket(SelectorProvider provider) {
    try {
        return provider.openServerSocketChannel();
    } catch (IOException e) {
        throw new ChannelException(
                "Failed to open a server socket.", e);
    }
}
public NioServerSocketChannel() {
    this(newSocket(DEFAULT_SELECTOR_PROVIDER));
}
public NioServerSocketChannel(ServerSocketChannel channel) {
    super(null, channel, SelectionKey.OP_ACCEPT);
    config = new NioServerSocketChannelConfig(this, javaChannel().socket());
}

继续调用父类AbstractNioChannel的构造函数

protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
    super(parent);
    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);
    }
}

继续调用父类AbstractChannel的构造函数

protected AbstractChannel(Channel parent) {
    this.parent = parent;
    id = newId();
    unsafe = newUnsafe();
    pipeline = newChannelPipeline();
}
3.1.2 ServerBootstrap.init()

ChannelPipeLine链表中中添加一个ChannelInitializer类型的事件处理,当Channel注册时会调用该initChannel()方法。

@Override
void init(Channel channel) {
    setChannelOptions(channel, options0().entrySet().toArray(newOptionArray(0)), logger);
    setAttributes(channel, attrs0().entrySet().toArray(newAttrArray(0)));

    ChannelPipeline p = channel.pipeline();

    final EventLoopGroup currentChildGroup = childGroup;
    final ChannelHandler currentChildHandler = childHandler;
    final Entry<ChannelOption<?>, Object>[] currentChildOptions =
            childOptions.entrySet().toArray(newOptionArray(0));
    final Entry<AttributeKey<?>, Object>[] currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(0));
    // AbstractUnsafe.register0()方法中的代码pipeline.invokeHandlerAddedIfNeeded();
    // 此段代码会调用以下的initChannel方法
    p.addLast(new ChannelInitializer<Channel>() {
        @Override
        public void initChannel(final Channel ch) {
            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));
                }
            });
        }
    });
}

继续查看DefaultChannelPipelineaddLast()方法,大概流程为:

  1. 将handler添加到pipeline的双向链表中。
  2. 如果未注册说明NioServerSocketChannel未绑定到NioEventLoop中,一旦注册则需要当前handler的handlerAdded()方法。
@Override
public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
    final AbstractChannelHandlerContext newCtx;
    synchronized (this) {
        checkMultiplicity(handler);

        newCtx = newContext(group, filterName(name, handler), handler);

        addLast0(newCtx);

        // If the registered is false it means that the channel was not registered on an eventLoop yet.
        // In this case we add the context to the pipeline and add a task that will call
        // ChannelHandler.handlerAdded(...) once the channel is registered.
        if (!registered) {
            newCtx.setAddPending();
            callHandlerCallbackLater(newCtx, true);
            return this;
        }

        EventExecutor executor = newCtx.executor();
        if (!executor.inEventLoop()) {
            callHandlerAddedInEventLoop(newCtx, executor);
            return this;
        }
    }
    callHandlerAdded0(newCtx);
    return this;
}
// 将handler封装成上下文环境ctx,插入到pipeline管道中
private AbstractChannelHandlerContext newContext(EventExecutorGroup group, String name, ChannelHandler handler) {
    return new DefaultChannelHandlerContext(this, childExecutor(group), name, handler);
}
3.1.3 EventLoopGroup.register()注册通道

大概流程:

  1. 调用主线程池中的线程NioEventLoop.register()方法,最终调用的是NioServerSocketChannel.unsafe.register()方法。
  2. NioServerSocketChannel绑定主线程池的一个NioEventLoop线程,之后Channel中的IO事件都交给该线程。
  3. 注册新连接的Channel到选择的NioEventLoop线程的Selector上,注册感兴趣的事件0,并绑定当前NioServerSocketChannel对象给SelectedKey,因此IO事件到来的时候能够获取到NioServerSocketChannel对象。
  4. 通知pipeline处理handler的handlerAdded()方法,最终执行ServerBootstrap.ChannelInitializer.initChannel()方法,即想pipeline中添加ServerBootstrapAcceptor,并移除当前ServerBootstrap.ChannelInitializer

查看NioEventLoopGroup类的register()方法,通过线程选择器轮询选择一个线程执行。

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

查看NioEventLoop类的register()方法,这里调用NioServerSocketChannel类的unsafe成员的register()方法,服务端的unsafeNioMessageUnsafe对象。

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

继续查看NioMessageUnsafe类的register()方法,调用父类AbstractUnsaferegister()方法,大概流程:

  1. 绑定NioServerSocketChannel所在的线程为轮询获取到的线程,即NioEventLoop,Netty的无锁串行化体现在这里。
  2. 由于线程未启动,所以会执行启动NioEventLoop线程,并添加注册任务到NioEventLoop的任务队列中。
  3. 注册新连接的Channel到选择的NioEventLoop线程的Selector上,注册感兴趣的事件0,,将当前NioServerSocketChannel对象绑定给SelectedKeyattach
@Override
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);
        }
    }
}
private void register0(ChannelPromise promise) {
    try {
        if (!promise.setUncancellable() || !ensureOpen(promise)) {
            return;
        }
        boolean firstRegistration = neverRegistered;
        // 注册感兴趣的事件并绑定SelctedKey的attach为NioServerSocketChannel
        doRegister();
        neverRegistered = false;
        registered = true;
        // 通知pipeline执行handlerAdded()方法
        pipeline.invokeHandlerAddedIfNeeded();
        safeSetSuccess(promise);
        pipeline.fireChannelRegistered();
        if (isActive()) {
            if (firstRegistration) {
                pipeline.fireChannelActive();
            } else if (config().isAutoRead()) {
                beginRead();
            }
        }
    } catch (Throwable t) {
        closeForcibly();
        closeFuture.setClosed();
        safeSetFailure(promise, t);
    }
}

AbstractNioChannel类的doRegister()方法

@Override
protected void doRegister() throws Exception {
    boolean selected = false;
    for (;;) {
        try {
            selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
            return;
        } catch (CancelledKeyException e) {
            if (!selected) {
                eventLoop().selectNow();
                selected = true;
            } else {
                throw e;
            }
        }
    }
}
3.2 AbstractBootstrap.doBind0()绑定地址和端口

等待通道注册成功后绑定地址,最终调用的是NioServerSocketChannel.unsafe.bind()方法。

  1. 绑定地址和端口。
  2. 注册SelectionKey.OP_ACCEPT 事件。
@Override
public final void bind(final SocketAddress localAddress, final ChannelPromise promise) {
    assertEventLoop();
    if (!promise.setUncancellable() || !ensureOpen(promise)) {
        return;
    }
    if (Boolean.TRUE.equals(config().getOption(ChannelOption.SO_BROADCAST)) &&
        localAddress instanceof InetSocketAddress &&
        !((InetSocketAddress) localAddress).getAddress().isAnyLocalAddress() &&
        !PlatformDependent.isWindows() && !PlatformDependent.maybeSuperUser()) {
        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;
    }
    if (!wasActive && isActive()) {
        invokeLater(new Runnable() {
            @Override
            public void run() {
                pipeline.fireChannelActive();
            }
        });
    }
    safeSetSuccess(promise);
}

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

注册SelectionKey.OP_ACCEPT 事件的逻辑有点长,继续看fireChannelActive()

@Override
public final ChannelPipeline fireChannelActive() {
    AbstractChannelHandlerContext.invokeChannelActive(head);
    return this;
}

执行HeadContext.active()方法。

@Override
public void channelActive(ChannelHandlerContext ctx) {
    ctx.fireChannelActive();
    readIfIsAutoRead();
}
private void readIfIsAutoRead() {
    if (channel.config().isAutoRead()) {
        channel.read();
    }
}

channel.read();最终执行的是DefaultChannelPipeline.read()方法。

@Override
public ChannelHandlerContext read() {
    final AbstractChannelHandlerContext next = findContextOutbound(MASK_READ);
    EventExecutor executor = next.executor();
    if (executor.inEventLoop()) {
        next.invokeRead();
    } else {
        Tasks tasks = next.invokeTasks;
        if (tasks == null) {
            next.invokeTasks = tasks = new Tasks(next);
        }
        executor.execute(tasks.invokeReadTask);
    }

    return this;
}

这里的nextHeadContext对象。

private void invokeRead() {
    if (invokeHandler()) {
        try {
            ((ChannelOutboundHandler) handler()).read(this);
        } catch (Throwable t) {
            notifyHandlerException(t);
        }
    } else {
        read();
    }
}
@Override
public void read(ChannelHandlerContext ctx) {
    unsafe.beginRead();
}

unsafe.beginRead()最终调用的是AbstractNioChannel.doBeginRead(),如果当前selectionKey为0 ,则重新绑定readInterestOp,这里的readInterestOp就是AbstractNioChannel的构造函数中传进来的SelectionKey.OP_ACCEPT

@Override
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);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值