Netty 源码分析系列(1)_主服务启动

本文详细解析了Netty服务端的启动流程,包括事件循环组(EventLoopGroup)的创建与配置,NioEventLoopGroup的工作原理,ServerBootstrap的使用方法以及关键组件如Channel、Handler的注册过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

public class MyServer {

    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.group(bossGroup, workerGroup)
                        .channel(NioServerSocketChannel.class)
                        .childHandler(new MyServerInitializer());

        ChannelFuture channelFuture = serverBootstrap.bind(8899).sync();
        channelFuture.channel().closeFuture().sync();

        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
    }
}
  • 创建两个事件循环组EventLoopGroup,即bossGroupworkerGroup

  • bossGroup接收事件后,转发给workerGroup

NioEventLoopGroup

构造函数如下:bossGroup的线程数通常指定为1

 

public NioEventLoopGroup() {
    this(0);
}

//指定线程个数
public NioEventLoopGroup(int nThreads) {
    this(nThreads, (Executor) null);
}

NioEventLoopGroup实现了 EventLoopGroup接口, EventLoopGroup文档说明:

// 提供将Channel可以注册到EventLoopGroup中的若干方法
public interface EventLoopGroup extends EventExecutorGroup {
    //返回下一个即将被使用的EventLoop
    @Override
    EventLoop next();

    //将Channel注册到EventLoop中,注册完成后,返回的ChannelFuture对象会得到通知
    ChannelFuture register(Channel channel);

    //传入的ChannelPromise对象在注册完成后也会得到通知
    ChannelFuture register(ChannelPromise promise);
}
  • ChannelPromise接口继承了ChannelFuture接口。

  • 构造函数中的其他参数的默认值:
  1. selectorProvider: SelectorProvider.provider()
  2. selectStrategyFactory:DefaultSelectStrategyFactory.INSTANCE
  3. rejectedExecutionHandler:RejectedExecutionHandlers.reject()
  • NioEventLoopGroup的父类MultithreadEventLoopGroup:

    ​ 当传入的nThreads线程数为0时,会使用默认线程数字段DEFAULT_EVENT_LOOP_THREADS,它的计算逻辑如下:

    public abstract class MultithreadEventLoopGroup extends MultithreadEventExecutorGroup implements EventLoopGroup {
    
        private static final int DEFAULT_EVENT_LOOP_THREADS;
    
        static {
            DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(
                    "io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));
        }
    
      
        protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {
            super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
        }
    }



2.线程工厂ThreadFactory和执行器Executor

MultithreadEventLoopGroup是之前提到的NioEventLoopGroup的父类,是一个抽象类。在上节中提到它有一套计算线程数量的逻辑

它继承自MultithreadEventExecutorGroup,而且真正的构造函数逻辑就在它的父类中。

 

MultithreadEventExecutorGroup

protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
                                            EventExecutorChooserFactory chooserFactory, Object... args) {
        ......
        //创建一个‘线程任务执行器’,传入一个线程工厂作为参数
        if (executor == null) {
            executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
        }
        ......
    }

ThreadFactory是一个接口,只定义了一个newThread 方法如下:

 

public interface ThreadFactory {
    Thread newThread(Runnable r);
}

线程工厂使得线程的创建线程的执行逻辑得到解耦,线程工厂可以设置线程的优先级、名字、是否后台线程、所属的ThreadGroup等信息。例如常用的工具类Executors的内部类DefaultThreadFactory就是接口ThreadFactory的一个实现类:

static class DefaultThreadFactory implements ThreadFactory {
        private static final AtomicInteger poolNumber = new AtomicInteger(1);
        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;

        DefaultThreadFactory() {
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() :
                                  Thread.currentThread().getThreadGroup();
            namePrefix = "pool-" +
                          poolNumber.getAndIncrement() +
                         "-thread-";
        }

        //创建新线程,设置是否后台运行,所属的ThreadGroup,优先级
        public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r,
                                  namePrefix + threadNumber.getAndIncrement(),
                                  0);
            if (t.isDaemon())
                t.setDaemon(false);
            if (t.getPriority() != Thread.NORM_PRIORITY)
                t.setPriority(Thread.NORM_PRIORITY);
            return t;
        }
    }

执行器接口--Executor

Executor接口是一个函数式接口,定义了一个execute方法:

 

public interface Executor {
    void execute(Runnable command);
}

上面的ThreadPerTaskExecutor就是Executor接口的实现类:

 

public final class ThreadPerTaskExecutor implements Executor {
    private final ThreadFactory threadFactory;

    public ThreadPerTaskExecutor(ThreadFactory threadFactory) {
        if (threadFactory == null) {
            throw new NullPointerException("threadFactory");
        }
        this.threadFactory = threadFactory;
    }

    @Override
    public void execute(Runnable command) {
        threadFactory.newThread(command).start();
    }
}

它持有一个线程工厂ThreadFactory对象,使用代理模式,执行时使用线程工厂创建了一个新的线程,并启动。

Executor接口提供了一种执行任务的新方式,不是直接新建线程并运行new Thread(Runnable).start()。创建Executor接口的实现类,将Runnable对象传入执行器中执行。

 

 Executor executor = new XXXExeutor();
 executor.execute(new RunnableTask1());
 executor.execute(new RunnableTask2());

具体例如:

  • 直接执行Runnable对象

    class DirectExecutor implements Executor {
        public void execute(Runnable r) {
           r.run();
        }
     }}
    
  • ThreadPerTaskExecutor的例子是新建了一个线程执行任务。

  • 将任务按照一定的顺序执行,如io.grpc.internal.SerializingExecutor, 它将任务首先添加到队列中,然后按序执行。

     public final class SerializingExecutor implements Executor, Runnable {
    
      private final Queue<Runnable> runQueue = new ConcurrentLinkedQueue<Runnable>();
    
      public SerializingExecutor(Executor executor) {
        Preconditions.checkNotNull(executor, "'executor' must not be null.");
        this.executor = executor;
      }
    
      //将任务添加到队列中,按序执行
      @Override
      public void execute(Runnable r) {
        runQueue.add(checkNotNull(r, "'r' must not be null."));
        schedule(r);
      }
    }
    

1. ServerBootstrap的使用:

通过链式的方式逐个调用groupchannelhandlerchildHandler方法,本质上是对需要的变量进行赋值

    ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.group(bossGroup, workerGroup)
                        .channel(NioServerSocketChannel.class)
                        .handler(new LoggingHandler(LogLevel.INFO))
                        .childHandler(new MyServerInitializer());

ServerBootStrap继承了抽象类AbstractBootstrap,作用是启动ServerChannel。一些重要的变量定义位于父类AbstractBootStrap中,而另一些位于子类ServerBootStrap中,下面会提到。

分解之后:

82:将参数 parentGroup 也就是bossGroup对象传入父类的group方法。

父类AbstractBootStrap的group方法如下:可以看到是将bossGroup对象赋值给父类的成员变量group

 

2.channel 方法:

 

channel方法位于父类中,本质是new一个ReflectiveChannelFactory,并赋值给父类的成员变量channelFactory在需要的时候,使用持有的channelFactory变量来创建channel

ReflectiveChannelFactory实现了ChannelFactory接口,它的newChannel方法调用传入的Class对象的

 

构造函数创建实例:

3. childHandler方法:

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

调用的堆栈:

总结1:

groupchannelchildHandler方法对变量groupchildGroupchannelFactorychildHandler变量进行了赋值。

 

总结2:

selector  是在new NioEventoop()时创建的。

selectionKey=javaChaneele().register(eventLoop,0,this);

最终监听OP_ACCEPT是通过bind完成后的firechnelACtivate 来出发的。

NioEventLOOP 是通过register操作的执行来完成的

 

相关log:

 

 

参考文档

https://www.jianshu.com/c/dfa503d2feac

### Netty 源码分析文章汇总 对于希望深入了解Netty源码的读者来说,一系列深入浅出的文章能够提供极大的帮助。以下是按照不同主题整理的一系列关于Netty源码解析的文章列表[^1]: #### 1. 初识Netty - **Netty入门**:介绍了Netty的基础概念及其优势所在。 #### 2. 核心组件剖析 - **Netty架构设计**:探讨了Netty的整体框架设计理念。 - **Channel详解**:解释了`Channel`接口的作用以及其实现方式。 - **ChannelHandler介绍**:描述了如何利用`ChannelHandler`处理网络事件。 - **ChannelPipeline**:讲述了消息传递过程中所经过的管道机制。 #### 3. 数据传输优化 - **字节缓冲区 ByteBuf(上下篇)**:详细解读了高效内存管理工具`ByteBuf`的工作原理。 - **Netty如何实现零拷贝**:讨论了减少数据复制开销的技术细节。 #### 4. 应用层协议支持 - **编程引导类 Bootstrap**:指导用户快速搭建基于Netty的应用程序。 - **Reactor模型**:阐述了异步I/O多路复用技术在Netty中的应用。 - **编解码器系列** - **编码器/解码器基础** - **自定义编解码器** #### 5. 启动流程揭秘 - **Server端启动过程源码分析**:逐步拆解服务器实例初始化直至监听端口绑定完成的关键步骤[^5]。 这些资源不仅适合初学者学习掌握基础知识,同时也非常适合有一定经验的研发人员进一步挖掘更深层次的功能特性。 ```java // 示例代码片段展示了NioServerSocketChannel的部分构造逻辑 public class NioServerSocketChannel extends AbstractNioMessageChannel { private final ServerSocketChannel javaChannel; public NioServerSocketChannel() throws ExceptionInInitializerError { this(ServerSocketChannel.open()); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

迅捷的软件产品制作专家

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值