netty 服务端的启动过程

服务端的启动过程

ServerBootstrap和Bootstrap的类图如下所示:

在这里插入图片描述

可以看到ServerBootstrap和Bootstrap都是继承自抽象类AbstractBootstrap。因为 ServerBootstrap 和 Bootstrap 大部分的方法和职责都是相同的,所以公共的逻辑由AbstractBootstrap类实现。

本文仅分享 ServerBootstrap 启动 Netty 服务端的过程

服务端启动代码如下:

// 创建 boss 线程组 用于服务端接受客户端的连接
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
// 创建 worker 线程组 用于进行 SocketChannel 的数据读写
EventLoopGroup workerGroup = new NioEventLoopGroup(); 
// 创建 EchoServerHandler 对象
final EchoServerHandler serverHandler = new EchoServerHandler();
try {
    // 创建 ServerBootstrap 对象
    ServerBootstrap b = new ServerBootstrap();
    b.group(bossGroup, workerGroup) // 设置使用的 EventLoopGroup
            .channel(NioServerSocketChannel.class) // 设置要被实例化的为 NioServerSocketChannel 类
            .option(ChannelOption.SO_BACKLOG, 100) // 设置 NioServerSocketChannel 的可选项
            .handler(new LoggingHandler(LogLevel.INFO)) // 设置 NioServerSocketChannel 的处理器
            .childHandler(new ChannelInitializer<SocketChannel>() {
                //设置连入服务端的 Client 的 SocketChannel 的处理器
                @Override
                public void initChannel(SocketChannel ch) throws Exception { 
                    ChannelPipeline p = ch.pipeline();
                    p.addLast(serverHandler);
                }
            });
    // 绑定端口,并同步等待成功,即启动服务端
    ChannelFuture f = b.bind(8090).sync();
    // 监听服务端关闭,并阻塞等待
    f.channel().closeFuture().sync();
} finally {
    // 优雅关闭两个 EventLoopGroup 对象
    bossGroup.shutdownGracefully();
    workerGroup.shutdownGracefully();
}

服务端启动代码主要包含两块逻辑:

1、设置启动器类(ServerBootstrap)的属性

2、绑定端口,启动服务端

1、设置启动器类(ServerBootstrap)的属性

1.1、设置线程组

public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
    super.group(parentGroup);//设置boss线程组
    if (childGroup == null) {
        throw new NullPointerException("childGroup");
    }
    if (this.childGroup != null) {
        throw new IllegalStateException("childGroup set already");
    }
    this.childGroup = childGroup;//设置work线程组
    return this;
}

1.2、设置服务端Channel

channel(Class<? extends C> channelClass)方法的主要逻辑是创建一个Channel实例的反射工厂,并将该反射工厂实例设置到ServerBootstrap的channelFactory属性中。

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

//反射工厂类,简单工厂
public class ReflectiveChannelFactory<T extends Channel> implements ChannelFactory<T> {

    private final Class<? extends T> clazz;

    public ReflectiveChannelFactory(Class<? extends T> clazz) {
        if (clazz == null) {
            throw new NullPointerException("clazz");
        }
        this.clazz = clazz;
    }

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

    @Override
    public String toString() {
        return StringUtil.simpleClassName(clazz) + ".class";
    }
}

//设置反射工厂
public B channelFactory(io.netty.channel.ChannelFactory<? extends C> channelFactory) {
    return channelFactory((ChannelFactory<C>) channelFactory);
}
//重载方法
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;//将反射工厂类设置到ServerBootstrap的channelFactory属性
    return self();
}

1.3、设置服务端通道的可选项

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

1.4、设置服务端通道的处理器

public B handler(ChannelHandler handler) {
    if (handler == null) {
        throw new NullPointerException("handler");
    }
    this.handler = handler;
    return self();
}

1.5、设置连入服务端的客户端连接的处理器

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

1.6 设置启动器类(ServerBootstrap)的属性小结

1、因为ServerBootstrap类的属性众多,故netty的作者使用了建造者设计模式消除构造函数参数过多的问题

2、有关ServerBootstrap属性设置的代码大多数都是直接给成员变量赋值,没有复杂的逻辑

2、绑定端口,启动服务端

因为绑定端口是ServerBootstrap和bootstrap共有的Api,故由其父类提供实现

调用父类AbstractBootstrap的bind(int inetPort)方法

public ChannelFuture bind(int inetPort) {
    return bind(new InetSocketAddress(inetPort));
}
// 调用重载的bind(SocketAddress localAddress)方法
public ChannelFuture bind(SocketAddress localAddress) {
    validate();//合法性校验
    if (localAddress == null) {
        throw new NullPointerException("localAddress");
    }
    return doBind(localAddress);
}
//调用doBind(final SocketAddress localAddress)方法
private ChannelFuture doBind(final SocketAddress localAddress) {
    //初始化并注册,返回一个ChannelFuture对象。因为是异步执行,所以ChannelFuture可以理解为一个执行结果的
    //占位符,在将来的某个时刻可以获得执行结果
    final ChannelFuture regFuture = initAndRegister();
    final Channel channel = regFuture.channel();
    if (regFuture.cause() != null) {
        return regFuture;
    }
    //因为initAndRegister()方法是异步的,所以执行到下面代码时通道的注册和初始化工作有可能尚未完成,
    //故需要对此进行分类讨论
    
	//如果此时 初始化和注册 已完成,则执行执行绑定端口方法
    if (regFuture.isDone()) {
        ChannelPromise promise = channel.newPromise();
        doBind0(regFuture, channel, localAddress, promise);
        return promise;
    } else {
        //如果此时初始化和注册操作未完成,则创建promise,并设置监听器,等待初始化和注册操作完成后的回调
        final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
        regFuture.addListener(new ChannelFutureListener() {
            //操作完成后回调,如果初始化和注册的过程中未发生任何异常,则会调用doBind0方法执行绑定操作
            @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;
    }
}

可以看到doBind方法逻辑为:

1、初始化并注册通道

2、绑定到指定的端口

接下来对上述两个步骤进行详细分析

2.1初始化并注册通道

final ChannelFuture initAndRegister() {
    Channel channel = null;
    try {
        //调用1.2中设置的channel反射工厂创建对应channel的实例,在这里就是创建NioServerSocketChannel
        channel = channelFactory.newChannel();
        init(channel);//初始化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);
    }
	//初始化完成后将当前通道实例注册到对应线程组(EventLoopGroup)中的线程(EventLoop)中
    ChannelFuture regFuture = config().group().register(channel);
    if (regFuture.cause() != null) {
        if (channel.isRegistered()) {
            channel.close();
        } else {
            channel.unsafe().closeForcibly();
        }
    }

    return regFuture;
}

initAndRegister()方法的大致逻辑为:

1、创建并初始化Channel实例

2、注册 Channel 到 EventLoopGroup 中

2.1.1创建并初始化Channel实例

因为服务端ServerBootstrap和客户端Bootstrap的初始化逻辑不同,故init的逻辑由子类实现,AbstractBootstrap类只提供抽象方法。

@Override
void init(Channel channel) throws Exception {
    //设置ChannelOption
    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(0));
    }
    synchronized (childAttrs) {
        currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(0));
    }

    p.addLast(new ChannelInitializer<Channel>() {
        //在Channel注册完成会被回调
        @Override
        public void initChannel(final Channel ch) throws Exception {
            final ChannelPipeline pipeline = ch.pipeline();
            // 添加用户配置的 ChannelHandler 到 pipeline 中。
            ChannelHandler handler = config.handler();
            if (handler != null) {
                pipeline.addLast(handler);
            }
			
            //添加 ServerBootstrapAcceptor到pipeline
            //确保是由channel绑定的eventLoop来执行
            ch.eventLoop().execute(new Runnable() {
                @Override
                public void run() {
                    pipeline.addLast(new ServerBootstrapAcceptor(
                            ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
                }
            });
        }
    });
}

2.1.2 注册 Channel 到 EventLoopGroup中

通过config().group() 获取boss线程组,调用register(Channel channel)方法完成注册

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

调用MultithreadEventLoopGroup的register(Channel channel)方法

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

next()方法会调用父类的事件执行选择器EventExecutorChooser在线程组中选择一个EventLoop执行注册操作

调用SingleThreadEventLoop#register(Channel channel)方法执行注册

@Override
public ChannelFuture register(Channel channel) {
    return register(new DefaultChannelPromise(channel, this));
}
//调用重载的register方法
@Override
public ChannelFuture register(final ChannelPromise promise) {
    ObjectUtil.checkNotNull(promise, "promise");
    //调用Channel的Unsafe的具体实现类(AbstractChannel类的内部类AbstractUnsafe)完成注册
    promise.channel().unsafe().register(this, promise);
    return promise;
}

AbstractChannel类的内部类AbstractUnsafe的register(EventLoop eventLoop, final ChannelPromise promise)方法

public final void register(EventLoop eventLoop, final ChannelPromise promise) {
    if (eventLoop == null) {
        throw new NullPointerException("eventLoop");
    }
    //判断当前channel是否已经被注册过,如果已经注册过则抛出非法状态异常
    if (isRegistered()) {
        promise.setFailure(new IllegalStateException("registered to an event loop already"));
        return;
    }
    //类型校验,校验 Channel 和 eventLoop 匹配,此时应该是NioEventLoop的子类
    if (!isCompatible(eventLoop)) {
        promise.setFailure(
                new IllegalStateException("incompatible event loop type: " + eventLoop.getClass().getName()));
        return;
    }

    AbstractChannel.this.eventLoop = eventLoop;
	
    //如果当前线程是channel绑定的EventLoop,则执行注册。否则,调用对应eventLoop执行
    //因为当前是服务端的启动,所以当前线程一定是Main线程,故会将注册任务交给绑定的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;
        //调用底层jdk的api将通道实例注册到对应的Selector上
        doRegister();
        neverRegistered = false;
        registered = true;
        //如果是第一次注册的话,则会执行一遍pipeline中的所有handler
        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);
    }
}
//实际注册的方法
@Override
protected void doRegister() throws Exception {
    boolean selected = false;
    for (;;) {
        try {
            //调用jdk的Channel实例注册到选择器中,并且声明感兴趣的事件为 0
            selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
            return;
        } catch (CancelledKeyException e) {
            if (!selected) {
                eventLoop().selectNow();
                selected = true;
            } else {
                throw e;
            }
        }
    }
}

DefaultChannelPipeline的invokeHandlerAddedIfNeeded()方法

final void invokeHandlerAddedIfNeeded() {
    assert channel.eventLoop().inEventLoop();//当前线程必须是channel绑定的eventLoop
    if (firstRegistration) {
        firstRegistration = false;
		//回调所有已经添加到pipeline中的Handler
        callHandlerAddedForAllHandlers();
    }
}

触发通道注册事件DefaultChannelPipeline#fireChannelRegistered(),在本例中主要作用就是调用LoggingHandler类打印日志

@Override
public final ChannelPipeline fireChannelRegistered() {
    AbstractChannelHandlerContext.invokeChannelRegistered(head);
    return this;
}

2.2绑定到指定的端口

初始化和注册通道的逻辑完成后接着会执行绑定端口操作,启动服务端

private static void doBind0(
        final ChannelFuture regFuture, final Channel channel,
        final SocketAddress localAddress, final ChannelPromise promise) {
	//调用channel通道对应的eventLoop执行绑定方法
    //此处调用channel.eventLoop()执行任务的原因是,此处代码会在register0()方法中的						//pipeline.fireChannelRegistered()方法之前执行,
    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());
            }
        }
    });
}

通道绑定端口的调用链如下所示:

AbstractChannel#bind(SocketAddress localAddress, ChannelPromise promise)

—>DefaultChannelPipeline#bind(SocketAddress localAddress, ChannelPromise promise)

—>AbstractChannelHandlerContext#bind(final SocketAddress localAddress, final ChannelPromise promise)

—>AbstractChannelHandlerContext#invokeBind(SocketAddress localAddress, ChannelPromise promise)

—>LoggingHandler#bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise)

—>AbstractChannelHandlerContext#bind(final SocketAddress localAddress, final ChannelPromise promise)

—>AbstractChannelHandlerContext#invokeBind(SocketAddress localAddress, ChannelPromise promise)

—>DefaultChannelPipeline#bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise)

—>AbstractUnsafe#bind(final SocketAddress localAddress, final ChannelPromise promise)

@Override
public final void bind(final SocketAddress localAddress, final ChannelPromise promise) {
    assertEventLoop();//必须是和channel相关联的Eventloop

    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();//当前Channel是否绑定对应端口
    try {
        doBind(localAddress);
    } catch (Throwable t) {
        safeSetFailure(promise, t);
        closeIfClosed();
        return;
    }
	//如果成功绑定指定端口,则触发通道Active事件
    if (!wasActive && isActive()) {
        invokeLater(new Runnable() {
            @Override
            public void run() {
                //触发通道Active事件
                pipeline.fireChannelActive();
            }
        });
    }

    safeSetSuccess(promise);
}
/**
* 调用jdk底层的Channel对象绑定指定端口
*
*/
@Override
protected void doBind(SocketAddress localAddress) throws Exception {
    if (PlatformDependent.javaVersion() >= 7) {
        javaChannel().bind(localAddress, config.getBacklog());
    } else {
        javaChannel().socket().bind(localAddress, config.getBacklog());
    }
}

触发通道Active事件

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

AbstractChannelHandlerContext.invokeChannelActive(head);方法最终会调用AbstractUnsafe的beginRead()方法

@Override
public final void beginRead() {
    // 判断是否在 EventLoop 的线程中。
    assertEventLoop();

    // Channel 必须激活
    if (!isActive()) {
        return;
    }

    // 执行开始读取
    try {
        doBeginRead();
    } catch (final Exception e) {
        invokeLater(new Runnable() {
            @Override
            public void run() {
                pipeline.fireExceptionCaught(e);
            }
        });
        close(voidPromise());
    }
}
// AbstractNioMessageChannel.java
@Override
protected void doBeginRead() throws Exception {
    if (inputShutdown) {
        return;
    }
    super.doBeginRead();
}

// AbstractNioChannel.java
@Override
protected void doBeginRead() throws Exception {
    final SelectionKey selectionKey = this.selectionKey;
    if (!selectionKey.isValid()) {
        return;
    }

    readPending = true;

    final int interestOps = selectionKey.interestOps(); //此时interestOps应该为0
    if ((interestOps & readInterestOp) == 0) { 
        //修改当前selector感兴趣的事件为Accept事件
        //也就说,设置完成后服务端就可以开始处理客户端的连接事件了
        selectionKey.interestOps(interestOps | readInterestOp);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章