Netty入门(十一)Netty服务器启动源码剖析

服务器示例代码:

 // Configure the server.
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
final EchoServerHandler serverHandler = new EchoServerHandler();
try {
    ServerBootstrap b = new ServerBootstrap();
    b.group(bossGroup, workerGroup)
     .channel(NioServerSocketChannel.class)
     .option(ChannelOption.SO_BACKLOG, 100)
     .handler(new LoggingHandler(LogLevel.INFO))
     .childHandler(new ChannelInitializer<SocketChannel>() {
         @Override
         public void initChannel(SocketChannel ch) throws Exception {
             ChannelPipeline p = ch.pipeline();
             if (sslCtx != null) {
                 p.addLast(sslCtx.newHandler(ch.alloc()));
             }
             //p.addLast(new LoggingHandler(LogLevel.INFO));
             p.addLast(serverHandler);
         }
     });

    // Start the server.
    ChannelFuture f = b.bind(PORT).sync();

    // Wait until the server socket is closed.
    f.channel().closeFuture().sync();

分析EventLoopGroup 对象

分析默认线程数

EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();

进入无参构造函数一直进入:

super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);

无参数nThreads 默认为0,因此nThreads==DEFAULT_EVENT_LOOP_THREADS

private static final int DEFAULT_EVENT_LOOP_THREADS;
static {
    DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(
            "io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));
}

发现DEFAULT_EVENT_LOOP_THREADS的默认值为cpu核数的两倍。

分析 EventLoopGroup 的过程

继续跟踪构造函数,发现抽象类 MultithreadEventExecutorGroup 的构造器方法MultithreadEventExecutorGroup,才是 NioEventLoopGroup 真正的构造方法。

    protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
                                            EventExecutorChooserFactory chooserFactory, Object... args) {
       //如果传入的执行器是空的,则采用默认的线程工厂new DefaultThreadFactory
       //和默认的执行器ThreadPerTaskExecutor(是一个线程池)                                      
        if (executor == null) {
            executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
        }
        //创建指定线程数的执行器数组,EventExecutor也是一个线程池
        children = new EventExecutor[nThreads];
        //初始化线程数组
        for (int i = 0; i < nThreads; i ++) {
            boolean success = false;
            try {
            	//创建new NioEventLoop并添加到执行器数组中,NioEventLoop也是线程池
                children[i] = newChild(executor, args);
                success = true;
            } catch (Exception e) {
                // TODO: Think about if this is a good exception type
                throw new IllegalStateException("failed to create a child event loop", e);
            } finally {
            	//如果创建失败,优雅关闭
                if (!success) {
                    for (int j = 0; j < i; j ++) {
                        children[j].shutdownGracefully();
                    }
                    for (int j = 0; j < i; j ++) {
                        EventExecutor e = children[j];
                        try {
                            while (!e.isTerminated()) {
                                e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
                            }
                        } catch (InterruptedException interrupted) {
                            // Let the caller handle the interruption.
                            Thread.currentThread().interrupt();
                            break;
                        }
                    }
                }
            }
        }
		//根据线程选择工厂创建一个线程选择器。
        chooser = chooserFactory.newChooser(children);

        final FutureListener<Object> terminationListener = new FutureListener<Object>() {
            @Override
            public void operationComplete(Future<Object> future) throws Exception {
                if (terminatedChildren.incrementAndGet() == children.length) {
                    terminationFuture.setSuccess(null);
                }
            }
        };
 		//为每一个单例线程池NioEventLoop,添加一个关闭监听器
        for (EventExecutor e: children) {
            e.terminationFuture().addListener(terminationListener);
        }

        Set<EventExecutor> childrenSet = new LinkedHashSet<EventExecutor>(children.length);
         //将所有的单例线程池添加到一个 HashSet 中
        Collections.addAll(childrenSet, children);
        readonlyChildren = Collections.unmodifiableSet(childrenSet);
    }

说明:
1)如果 executornull,使用 Netty 默认的线程工厂DefaultThreadFactory,创建一个默认的 ThreadPerTaskExecutor作为执行器。
2)根据传入的线程数(CPU*2)创建一个线程池(单例线程池)数组EventExecutor
3)循环填充数组中的元素,创建new NioEventLoop并添加到执行器数组中。如果异常,则关闭所有的单例线程池NioEventLoopNioEventLoop本身就是线程池。
4)根据线程选择工厂创建一个 线程选择器。
5)为每一个单例线程池添加一个关闭监听器。
6)将所有的单例线程池添加到一个 HashSet 中。

ServerBootstrap 创建和构造过程

ServerBootstrap 是个空构造,但是有默认的成员变量
private final Map<ChannelOption<?>, Object> childOptions = new LinkedHashMap<ChannelOption<?>, Object>();
private final Map<AttributeKey<?>, Object> childAttrs = new LinkedHashMap<AttributeKey<?>, Object>();
//config 对象,会在后面起很大作用
private final ServerBootstrapConfig config = new ServerBootstrapConfig(this);
private volatile EventLoopGroup childGroup;
private volatile ChannelHandler childHandler;
分析一下 ServerBootstrap 基本使用情况
  b.group(bossGroup, workerGroup)
     .channel(NioServerSocketChannel.class)
     .option(ChannelOption.SO_BACKLOG, 100)
     .handler(new LoggingHandler(LogLevel.INFO))
     .childHandler(new ChannelInitializer<SocketChannel>() {
         @Override
         public void initChannel(SocketChannel ch) throws Exception {
             ChannelPipeline p = ch.pipeline();
             if (sslCtx != null) {
                 p.addLast(sslCtx.newHandler(ch.alloc()));
             }
             //p.addLast(new LoggingHandler(LogLevel.INFO));
             p.addLast(serverHandler);
         }
     });

说明:
1)链式调用:group方法,将bossGroupworkerGroup传入,bossGroup赋值给parentGroup属性,workerGroup赋值给 childGroup 属性
2)channel 方法传入NioServerSocketChannel.class对象。会根据这个 class ,通过反射创建 NioServerSocketChannel构造器对象并把这个对象封装到ChannelFactory中,返回ServerBootstrap
3)option 方法传入 TCP 参数,放在一个ConcurrentHashMap中。
4)handler 方法传入一个 handler 中,这个hanlder 只专属于 ServerSocketChannel 而不是 SocketChannel(客户端那个)
5)childHandler 传入一个 hanlder ,这个handler 将会在每个客户端连接的时候调用。供 SocketChannel 使用

绑定端口的分析

服务器就是在这个bind方法里启动完成的

ChannelFuture f = b.bind(PORT).sync();
public ChannelFuture bind(SocketAddress localAddress) {
    validate();
    return doBind(ObjectUtil.checkNotNull(localAddress, "localAddress"));
}
核心代码doBind

核心是两个方法 initAndRegisterdoBind0

    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 方法,完成对端口的绑定
             //============================================
            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
final ChannelFuture initAndRegister() {
    Channel channel = null;
    // ...
    channel = channelFactory.newChannel();
    //...
    init(channel);
    //...
    ChannelFuture regFuture = config().group().register(channel);
    //...
    return regFuture;
}

initAndRegister里面做了三件事情

  1. new一个channel
  2. init这个channel
  3. 将这个channel 注册到某个对象
new一个channel

我们发现这条channel是通过一个 channelFactory new出来的,跟进入最终是调用到 ReflectiveChannelFactory.newChannel() 方法

 public T newChannel() {
     try {//这个构造器就是之前创建的
         return constructor.newInstance();
     } catch (Throwable t) {
         throw new ChannelException("Unable to create Channel from class " + constructor.getDeclaringClass(), t);
     }
 }

通过反射的方式来创建一个对象,而这个class就是我们在ServerBootstrap中传入的NioServerSocketChannel.class
接下来我们就可以将重心放到 NioServerSocketChannel的默认构造函数。

private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();
public NioServerSocketChannel() {
    this(newSocket(DEFAULT_SELECTOR_PROVIDER));
}
private static ServerSocketChannel newSocket(SelectorProvider provider) {
    //...
    return provider.openServerSocketChannel();
}

通过SelectorProvider.openServerSocketChannel()创建一条serverchannel,然后进入到以下方法:

public NioServerSocketChannel(ServerSocketChannel channel) {
    super(null, channel, SelectionKey.OP_ACCEPT);
    //创建一个NioServerSocketChannelConfig
    //主要用于向外展示NioServerSocketChannel的一些配置信息
    config = new NioServerSocketChannelConfig(this, javaChannel().socket());
}
protected AbstractNioMessageChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
   super(parent, ch, readInterestOp);
}

这个readInterestOp变量是SelectionKey.OP_ACCEPT枚举的值,这里我们要加深下印象,后面会用到这个变量:

    protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
        super(parent);
        this.ch = ch;
        this.readInterestOp = readInterestOp;
        try {
            ch.configureBlocking(false);
        } catch (IOException e) {
。。。。
    }

NioServerSocketChannel的最终构造,主要可以分为3点:

protected AbstractChannel(Channel parent) {
    this.parent = parent;
    id = newId();
    unsafe = newUnsafe();//空构造,不看
    pipeline = newChannelPipeline();
}
  • 调用newId(),生成一个全局Id,这个我们不讲解
  • 调用newUnsafe(),生成NioMessageUnsafe对象,这个对象很关键,包括后面的NioServerSocketChannel往Selector注册ACCEPT事件、NioServerSocketChannel绑定端口都需要用到这个对象。
  • 调用newChannelPipeline(),生成DefaultChannelPipeline对象,这个ChannelPipeline我们很熟悉,就是Netty非常出名的调用链对象。

继续往下看newChannelPipeline():

protected DefaultChannelPipeline newChannelPipeline() {
    return new DefaultChannelPipeline(this);
}
protected DefaultChannelPipeline(Channel channel) {
    this.channel = ObjectUtil.checkNotNull(channel, "channel");
    succeededFuture = new SucceededChannelFuture(channel, null);
    voidPromise =  new VoidChannelPromise(channel, true);

    tail = new TailContext(this);//TailContext为AbstractChannelHandlerContext
    head = new HeadContext(this);//HeadContext为AbstractChannelHandlerContext

    head.next = tail;
    tail.prev = head;
}

由上面代码我们可以了解到ChannelPipeline的构造过程,总结为以下几点

  • 每个channelpipeline都和一个channel绑定,不管是NioServerSocketChannel还是NioSocketChannel。当然我们这里的这个channelNioServerSocketChannel
  • ChannelPipeline它是一个双向循环链表结构,链表中的元素为AbstractChannelHandlerContext对象,那为什么我们往ChannelPipeline中添加的是ChannelHandler对象?因为每次用户添加ChannelHandler对象的时候,Netty会自动把ChannelHandler包装成AbstractChannelHandlerContext对象,在插入链表中。
  • 初始化过程中,会自动创建头结点和尾结点,分别为HeadContextTailContext

此时channelpipeline的双向链表结构如下:
在这里插入图片描述
总结:创建channel主要干了什么事情。
1.使用channelFactory创建channel
2.设置相关属性,如:生成一个全局Id,创建管道
3.管道是双向链表结构,初始化的时候自动添加头结点和为节点,都是ChannelHandlerContext

到此为止NioServerSocketChannel的对象构造完毕。

初始化channel
    void init(Channel channel) {
    //设置option和attr,先调用options0()以及attrs0()
    //然后将得到的options和attrs注入到channelConfig或者channel中
        setChannelOptions(channel, options0().entrySet().toArray(newOptionArray(0)), logger);
        setAttributes(channel, attrs0().entrySet().toArray(newAttrArray(0)));
		//获取channel的pipeline
        ChannelPipeline p = channel.pipeline();

        final EventLoopGroup currentChildGroup = childGroup;
        final ChannelHandler currentChildHandler = childHandler;
        //设置新接入channel的option和attr
        final Entry<ChannelOption<?>, Object>[] currentChildOptions =
                childOptions.entrySet().toArray(newOptionArray(0));
        final Entry<AttributeKey<?>, Object>[] currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(0));
		//调用pipeline.addLast()往pipeline添加一个ChannelInitializer对象,
		//ChannelInitializer对象的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));
                    }
                });
            }
        });
    }

我们看一下pipelineaddLast()方法:

@Override
public final ChannelPipeline addLast(ChannelHandler... handlers) {
    return addLast(null, handlers);
}
public final ChannelPipeline addLast(EventExecutorGroup executor, ChannelHandler... handlers) {
    for (ChannelHandler h: handlers) {
        if (h == null) {
            break;
        }
        addLast(executor, null, h);
    }
    return this;
}
@Override
public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
   final AbstractChannelHandlerContext newCtx;
   synchronized (this) {
       checkMultiplicity(handler);
	   //把handler包装成AbstractChannelHandlerContext对象
       newCtx = newContext(group, filterName(name, handler), handler);
	   //把上面生成的AbstractChannelHandlerContext对象添加到双向链表中
       addLast0(newCtx);

//如果该channel还没有注册,那么调用callHandlerCallbackLater(newCtx,true),延迟执行该
//AbstractChannelHandlerContext的handlerAdded()方法,即把该AbstractChannelHandlerContext加入
//一个单链表中,那么一旦该channel注册到NioEventLoop中,就会马上执行该单链表上的
//AbstractChannelHandlerContext的handlerAdded方法(很显然,我们现在channel还没有注册,所以会加入到单链表中)
       if (!registered) {
           newCtx.setAddPending();
           callHandlerCallbackLater(newCtx, true);
           return this;
       }

       EventExecutor executor = newCtx.executor();
       if (!executor.inEventLoop()) {
           newCtx.setAddPending();
           executor.execute(new Runnable() {
               @Override
               public void run() {
                   callHandlerAdded0(newCtx);
               }
           });
           return this;
       }
   }
   //调用callHandlerAdded0(newCtx),即执行AbstractChannelHandlerContext的handlerAdded()方法
   //为什么上面说延迟执行handlerAdded(),等到注册完后在执行,这里又说要执行handlerAdded()?因为有
  //些AbstractChannelHandlerContext的handlerAdded()是不需要注册后才执行的(也就是不需要延迟执
  //行)。因为我们这里添加的是ChannelInitializer对象,我们看下ChannelInitializer源码便清楚。
   callHandlerAdded0(newCtx);
   return this;
}

说明:

  • 调用newCtx = newContext(group, filterName(name, handler),
    handler),把handler包装成AbstractChannelHandlerContext对象
  • 调用addLast0(newCtx),把上面生成的AbstractChannelHandlerContext对象添加到双向链表中
private void addLast0(AbstractChannelHandlerContext newCtx) {
     AbstractChannelHandlerContext prev = tail.prev;
     newCtx.prev = prev;
     newCtx.next = tail;
     prev.next = newCtx;
     tail.prev = newCtx;
 }
  • 如果该channel还没有注册,那么调用callHandlerCallbackLater(newCtx,true),延迟执行该AbstractChannelHandlerContext的handlerAdded()方法,即把该AbstractChannelHandlerContext加入一个单链表中,那么一旦该channel注册到NioEventLoop中,就会马上执行该单链表上的AbstractChannelHandlerContext的handlerAdded方法(很显然,我们现在channel还没有注册,所以会加入到单链表中)
if (!registered) {
	newCtx.setAddPending();
	 callHandlerCallbackLater(newCtx, true);
	 return this;
}
private void callHandlerCallbackLater(AbstractChannelHandlerContext ctx, boolean added) {
    assert !registered;
    PendingHandlerCallback task = added ? new PendingHandlerAddedTask(ctx) : new PendingHandlerRemovedTask(ctx);
    // pendingHandlerCallbackHead是单链表结构
    PendingHandlerCallback pending = pendingHandlerCallbackHead;
    if (pending == null) {
        pendingHandlerCallbackHead = task;
    } else {
        // Find the tail of the linked-list.
        while (pending.next != null) {
            pending = pending.next;
        }
        pending.next = task;
    }
}
  • 调用callHandlerAdded0(newCtx),即执行AbstractChannelHandlerContext的handlerAdded()方法
    为什么上面说延迟执行handlerAdded(),等到注册完后在执行,这里又说要执行handlerAdded()?因为有些AbstractChannelHandlerContext的handlerAdded()是不需要注册后才执行的(也就是不需要延迟执行)。因为我们这里添加的是ChannelInitializer对象,我们看下ChannelInitializer源码便清楚。
private void callHandlerAdded0(final AbstractChannelHandlerContext ctx) {
    try {
        ctx.handler().handlerAdded(ctx);
        ctx.setAddComplete();
    } catch (Throwable t) {
       ...省略
    }
}
 @Override
 public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
     if (ctx.channel().isRegistered()) {
//很显然了,这里首先获取了channel,并且判断了该channel是否注册到NioEventLoop,
//很显然,目前来说还没有,所以initChannel(ctx)方法并没有执行。
         initChannel(ctx);
     }
 }

那么此时pipeline中的数据结构如下图:
在这里插入图片描述
总结:
初始化管道主要做了啥
1.进行一些option的配置
2.进行一些attr的配置
3.调用pipeline.addLast()pipeline添加一个ChannelInitializer对象

到此为止channelpipe.addLast()方法就分析完毕了,而且init(channel)也走完了

将这个channel 注册到某个对象
    ChannelFuture regFuture = config().group().register(channel);

这里创建了DefaultChannelPromise对象,很显然等一下会使用到异步调用:

SingleThreadEventLoop.java
public ChannelFuture register(Channel channel) {
    return register(new DefaultChannelPromise(channel, this));
}
//继续根据,省略中间一些步骤
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;
    }
//在channel设置NioEventLoop,标记该Channel是由那个NioEventLoop来管理的
    AbstractChannel.this.eventLoop = eventLoop;
	//判断当前线程是否在NioEventLoop线程中
    if (eventLoop.inEventLoop()) {
    	//如果在,那么直接在同步调用register0(promise)方法
        register0(promise);
    } else {
        try {
        //如果不在,那么把register0(promise)方法包装一个Task放入NioEventLoop的队列中
        //让NioEventLoop线程池异步执行。
            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);
        }
    }
}

很显然,当前我们还在Main线程中,不在NioEventLoop这个线程中,所以它会先返回结果,在异步执行register0(promise)

因为是异步执行的register0(promise)方法,所以我们暂且先不跟这个方法,我们先回到调用的起点,也就是initAndRegister()中

final ChannelFuture initAndRegister() {
    Channel channel = null;
    // ...
    channel = channelFactory.newChannel();
    //...
    init(channel);
    //...
    ChannelFuture regFuture = config().group().register(channel);
    //...
    return regFuture;
}

那么现在initAndRegister()调用也走完了,返回ChannelFuturedoBind(),这个regFuture 就是异步执行register0(promise)中的promise

    private ChannelFuture doBind(final SocketAddress localAddress) {
        final ChannelFuture regFuture = initAndRegister();
        final Channel channel = regFuture.channel();
        if (regFuture.cause() != null) {
            return regFuture;
        }
		//判断regFuture异步调用是否已经完成
        if (regFuture.isDone()) {
            // At this point we know that the registration was complete and successful.
            ChannelPromise promise = channel.newPromise();
             //============================================
             //说明:执行 doBind0 方法,完成对端口的绑定
             //============================================
            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()方法后

  • 首先判断该future,是否isDone(),如果是,那么直接调用doBind0(regFuture, channel,localAddress, promise)
  • 如果不是,那么往future中加入一个监听器,为了好记我们称它为"RegisterListener",在监听器里面去调用doBind0(regFuture, channel, localAddress, promise);

我们这分析的时候future是没有完成的,它会走监听器,具体什么时候调用监听器呢?我们这时候回到刚刚异步执行的register0(promise)方法,这个方法在AbstractUnsafe类下,AbstractUnsafeAbstractChannel的内部类,所以AbstractChannel类的属性,在AbstractUnsafe类下也可以访问。

AbstractUnsafe.java
private void register0(ChannelPromise promise) {
    try {
        if (!promise.setUncancellable() || !ensureOpen(promise)) {
            return;
        }
        boolean firstRegistration = neverRegistered;
        //往NioEventLoop的Selector注册。
        doRegister();
        neverRegistered = false;
        //把channel的registered变量标记为true
        registered = true;
		//之前我们调用pipeline.addLast()讲的延迟调用,一旦注册后,
		//就立马执行单链表上的channelHandler,那么这个单链表上的channelHandler就是在这依次被调用
        pipeline.invokeHandlerAddedIfNeeded();
		
		//触发promise的监听器的operationComplete()方法。
        safeSetSuccess(promise);
        //触发pipeline中的inboundchannelHandler的channelRegistered()方法
        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.
        if (isActive()) {
            if (firstRegistration) {
            	//获取channel的绑定状态,如果已经绑定端口,而且是第一次注册,
            	//那么调用pipeline.fireChannelActive();
                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);
    }
}

1、doRegister()

AbstractNioChannel.java
@Override
    protected void doRegister() throws Exception {
        boolean selected = false;
        for (;;) {
            try {
                selectionKey = javaChannel().register(eventLoop().selector, 0, this);
                return;
            } catch (CancelledKeyException e) {
  。。。
            }
        }
    }
  • 这里注册的事件是0,即什么事件也不监听。
  • 这里可能会有疑问?为什么不直接注册ACCEPT事件,因为目前来说channel还没有绑定端口,那么现在注册ACCEPT事件也没什么意义。

2、pipeline.invokeHandlerAddedIfNeeded();

DefaultChannelPipeline.java
final void invokeHandlerAddedIfNeeded() {
 assert channel.eventLoop().inEventLoop();
  if (firstRegistration) {
      firstRegistration = false;
      callHandlerAddedForAllHandlers();
  }
}
DefaultChannelPipeline.java
private void callHandlerAddedForAllHandlers() {
final PendingHandlerCallback pendingHandlerCallbackHead;
synchronized (this) {
    assert !registered;

    // This Channel itself was registered.
    registered = true;

    pendingHandlerCallbackHead = this.pendingHandlerCallbackHead;
    // Null out so it can be GC'ed.
    this.pendingHandlerCallbackHead = null;
}

// This must happen outside of the synchronized(...) block as otherwise handlerAdded(...) may be called while
// holding the lock and so produce a deadlock if handlerAdded(...) will try to add another handler from outside
// the EventLoop.
PendingHandlerCallback task = pendingHandlerCallbackHead;
while (task != null) {
    task.execute();
    task = task.next;
}
}
PendingHandlerAddedTask.java
@Override
void execute() {
    EventExecutor executor = ctx.executor();
    if (executor.inEventLoop()) {
    //里面就是执行
        callHandlerAdded0(ctx);
    } else {
        try {
            executor.execute(this);
        } catch (RejectedExecutionException e) {
            if (logger.isWarnEnabled()) {
                logger.warn(
                        "Can't invoke handlerAdded() as the EventExecutor {} rejected it, removing handler {}.",
                        executor, ctx.name(), e);
            }
            remove0(ctx);
            ctx.setRemoved();
        }
    }
}
private void callHandlerAdded0(final AbstractChannelHandlerContext ctx) {
    try {
        ctx.handler().handlerAdded(ctx);
        ctx.setAddComplete();
    } catch (Throwable t) {
       ...省略
    }
}
 @Override
 public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
     if (ctx.channel().isRegistered()) {
//很显然了,这里首先获取了channel,并且判断了该channel是否注册到NioEventLoop,
//很显然,目前来说注册了,所以initChannel(ctx)方法被执行。
         initChannel(ctx);
     }
 }

还记得我们往单链表pendingHandlerCallbackHead添加了一个ChannelInitializer对象,我们回顾一下

ServerBootstrap.java  init()中一个片段
p.addLast(new ChannelInitializer<Channel>() {
      @Override
      public void initChannel(Channel ch) throws Exception {
          final ChannelPipeline pipeline = ch.pipeline();
          //首先获取handler
          ChannelHandler handler = config.handler();
          if (handler != null) {
          	//添加handler
              pipeline.addLast(handler);
          }
          //往管理channel的NioEventLoop的队列中插入一个Task
          ch.eventLoop().execute(new Runnable() {
              @Override
              public void run() {
                  pipeline.addLast(new ServerBootstrapAcceptor(
                          currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
              }
          });
      }
  });
  

那么此时就会执行ChannelInitializer对象的handlerAdded()方法,并且因为已经注册了,那么就会执行initChannel(ctx)方法

  • 首先获取handler,即是最开始模板代码中我们调用ServerBootstrap.handler(new
    LoggingHandler())。
  • 然后往管理channelNioEventLoop的队列中插入一个Task
    那么此时pipeline中数据结构为,如下:
    在这里插入图片描述
    3、然后执行safeSetSuccess(promise);,即通知往promise自己注册的所有监听器,那么这时候我们要回到AbstractBoostrapdoBind(final SocketAddress localAddress)方法中
AbstractBoostrap.java doBind(final SocketAddress localAddress) 的一个片段
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);
       }
   }
});

那么这时候会执行operationComplete()方法,然后调用 doBind0(regFuture, channel, localAddress, promise);

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

这里往channelNioEventLoop队列里插入一个Task,因为NioEventLoop是个单线程线程池,因为该NioEventLoop正在执行register0(promise)这个方法,所以这个Task不会立马被执行,而是等register0(promise)执行完后才执行。所以我们回到register0(promise)方法。

4、pipeline.fireChannelRegistered();调用pipleline中的双向链表中的inbound HandlerchannelRegistered()方法
在这里插入图片描述
此时register0(promise)就执行完毕了,刚刚我们往负责ChannelNioEventLoop的队列中丢入了一个Task,那么现在它会被执行。

AbstractBoostrap.java
private static void doBind0(
       final ChannelFuture regFuture, final Channel channel,
       final SocketAddress localAddress, final ChannelPromise promise) {
   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.bind(localAddress, promise)

AbstractChannel.java
@Override
    public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
        return pipeline.bind(localAddress, promise);
    }
    DefaultChannelPipeline.java
 @Override
    public final ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
        return tail.bind(localAddress, promise);
    }
    AbstractChannelHandlerContext.java
 @Override
    public ChannelFuture bind(final SocketAddress localAddress, final ChannelPromise promise) {
        if (localAddress == null) {
            throw new NullPointerException("localAddress");
        }
        if (!validatePromise(promise, false)) {
            // cancelled
            return promise;
        }
        //首先调用findContextOutbound(),从链表的的尾部往前找属于outbound的
        final AbstractChannelHandlerContext next = findContextOutbound();
        EventExecutor executor = next.executor();
        if (executor.inEventLoop()) {
        	//然后调用AbstractChannelHandlerContext 的invokeBind(localAddress, promise);
            next.invokeBind(localAddress, promise);
        } else {
            safeExecute(executor, new Runnable() {
                @Override
                public void run() {
                    next.invokeBind(localAddress, promise);
                }
            }, promise, null);
        }
        return promise;
    }
  • 首先调用findContextOutbound(),从链表的的尾部往前找属于outbound的AbstractChannelHandlerContext
  • 然后调用AbstractChannelHandlerContext 的invokeBind(localAddress, promise);
AbstractChannelHandlerContext.java
private AbstractChannelHandlerContext findContextOutbound() {
    AbstractChannelHandlerContext ctx = this;
    do {
        ctx = ctx.prev;
    } while (!ctx.outbound);
    return ctx;
}
private void invokeBind(SocketAddress localAddress, ChannelPromise promise) {
    if (invokeHandler()) {
        try {
            ((ChannelOutboundHandler) handler()).bind(this, localAddress, promise);
        } catch (Throwable t) {
            notifyOutboundHandlerException(t, promise);
        }
    } else {
        bind(localAddress, promise);
    }
}

直接调用handler的bind()方法

我们首先回顾一下当前pipeline中的双向链表:
在这里插入图片描述
这里比较关键的属于outbound的channelHandler为HeadContext,我们直接看HeadContext的bind()方法:

HeadContext.java
 @Override
public void bind(
        ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise)
        throws Exception {
    unsafe.bind(localAddress, promise);
}
AbstractUnsafe.java
@Override
public final void bind(final SocketAddress localAddress, final ChannelPromise promise) {
....
    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);
}

这个方法是整个Netty服务端绑定端口的最核心的方法

  • doBind(localAddress);绑定端口
  • pipeline.fireChannelActive();往pipeline中传递channelActive事件

1、 doBind(localAddress);

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

这里很熟悉了,用到了NIO的API,根据JDK版本

  • 如果>=7,ServerSocketChannel.bind(SocketAddress,config.getBacklog())
  • 否则,ServerSocketChannel.socket().bind(SocketAddress,config.getBacklog())

2、pipeline.fireChannelActive();往pipeline中传递channelActive事件

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

这里的head是双向链表的头指针,即为HeadContext

AbstractChannelHandlerContext.java
static void invokeChannelActive(final AbstractChannelHandlerContext next) {
    EventExecutor executor = next.executor();
    if (executor.inEventLoop()) {
        next.invokeChannelActive();
    } else {
        executor.execute(new Runnable() {
            @Override
            public void run() {
                next.invokeChannelActive();
            }
        });
    }
}
private void invokeChannelActive() {
    if (invokeHandler()) {
        try {
            ((ChannelInboundHandler) handler()).channelActive(this);
        } catch (Throwable t) {
            notifyHandlerException(t);
        }
    } else {
        fireChannelActive();
    }
}

直接调用HeadContextchannelActive()方法

@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
   ctx.fireChannelActive()
   readIfIsAutoRead();
}

首先把channelActive事件往下传递,因为其他channelHandler都不是关键,我们就不往下看了,然后调用readIfIsAutoRead();

HeadContext.java
 private void readIfIsAutoRead() {
            if (channel.config().isAutoRead()) {
                channel.read();
            }
        }
AbstractChannel.java
    @Override
    public Channel read() {
        pipeline.read();
        return this;
    }
DefaultChannelPipeline.java
 @Override
    public final ChannelPipeline read() {
        tail.read();
        return this;
    }
    @Override
    public ChannelHandlerContext read() {
        final AbstractChannelHandlerContext next = findContextOutbound();
        EventExecutor executor = next.executor();
        if (executor.inEventLoop()) {
            next.invokeRead();
        } else {
            Runnable task = next.invokeReadTask;
            if (task == null) {
                next.invokeReadTask = task = new Runnable() {
                    @Override
                    public void run() {
                        next.invokeRead();
                    }
                };
            }
            executor.execute(task);
        }
        return this;
    }

从双向链表的尾指针开始往前找outboundChannelHandler,然后调用ChannelHandlerread()方法
在这里插入图片描述
这里找到的最关键的ChannelHandler 就是HeadContext,所以我们来看HeadContextread()

HeadContext.java
@Override
public void read(ChannelHandlerContext ctx) {
    unsafe.beginRead();
}
AbstractUnsafe.java
public final void beginRead() {
      assertEventLoop();
      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 {
    // 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);
    }
}

OK,readInterestOp就是之前的SelectionKey.OP_ACCEPT的值,又是我们很熟悉的NIO的API,通过selectionKey .interestOps()注册一个ACCEPT事件。

到此为止,Netty服务端的绑定端口源码执行完毕。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值