Netty-Netty服务器的启动源码简单分析

Netty服务器的启动源码分析

  • 源码剖析

    • 源码需要剖析到Netty调用doBind方法,追踪到NioServerSocketChannel的doBind方法
    • 并且Debug程序到NioEventLoop类的run代码,无限循环,在服务器端运行。
  • netty服务器创建的代码

    • /*
       * Copyright 2012 The Netty Project
       *
       * The Netty Project licenses this file to you under the Apache License,
       * version 2.0 (the "License"); you may not use this file except in compliance
       * with the License. You may obtain a copy of the License at:
       *
       *   http://www.apache.org/licenses/LICENSE-2.0
       *
       * Unless required by applicable law or agreed to in writing, software
       * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
       * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
       * License for the specific language governing permissions and limitations
       * under the License.
       */
      package com.jl.java.web.source.echo;
      
      import io.netty.bootstrap.ServerBootstrap;
      import io.netty.channel.*;
      import io.netty.channel.nio.NioEventLoopGroup;
      import io.netty.channel.socket.SocketChannel;
      import io.netty.channel.socket.nio.NioServerSocketChannel;
      import io.netty.handler.logging.LogLevel;
      import io.netty.handler.logging.LoggingHandler;
      import io.netty.handler.ssl.SslContext;
      import io.netty.handler.ssl.SslContextBuilder;
      import io.netty.handler.ssl.util.SelfSignedCertificate;
      
      /**
       * Echoes back any received data from a client.
       */
      public final class EchoServer {
      
          static final boolean SSL = System.getProperty("ssl") != null;
          static final int PORT = Integer.parseInt(System.getProperty("port", "8007"));
      
          public static void main(String[] args) throws Exception {
              // Configure SSL.
              final SslContext sslCtx;
              if (SSL) {
                  SelfSignedCertificate ssc = new SelfSignedCertificate();
                  sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
              } else {
                  sslCtx = null;
              }
      
              // Configure the server.
              EventLoopGroup bossGroup = new NioEventLoopGroup(1);
              EventLoopGroup workerGroup = new NioEventLoopGroup();
              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(new EchoServerHandler());
                       }
                   });
      
                  // Start the server.
                  ChannelFuture f = b.bind(PORT).sync();
      
                  // Wait until the server socket is closed.
                  f.channel().closeFuture().sync();
              } finally {
                  // Shut down all event loops to terminate all threads.
                  bossGroup.shutdownGracefully();
                  workerGroup.shutdownGracefully();
              }
          }
      }
      
  • 从上述代码中可以看出Netty服务端创建逻辑可以分以下几个步骤

    • 创建BossGroup EventLoopGroup bossGroup = new NioEventLoopGroup(1);
    • 创建WorkerGroup EventLoopGroup workerGroup = new NioEventLoopGroup();
    • 创建服务器启动类对象ServerBootstrap ServerBootstrap b = new ServerBootstrap();
    • 调用serverbootStrap goup()方法,添加bossGroup 和 workerGroup
    • 调用serverBootstrap的Channel()方法,为Netty定义IO模型为NIO,传入NioServerSocketChannel,
    • 调用serverBootstrap的option方法,设置参数,SO_BACKLOG,SO_KEEPALIVE
    • 调用serverBootstrap的handler()方法,为bossGroup添加 事件控制器
    • 调用serverBootstrap的childHandler()方法,为workerGroup添加事件控制器
      • 添加的是ChannelInitializer接口的对象,通过重写initChannel方法,来在方法中,通过channel.pipeline()获取到ChannelPipeline
      • 调用ChannelPipline.addLast()方法向pipeline添加所需要的入站出站事件逻辑
    • 调用serverBootstrap的bind()方法,监听端口,等待客户端连接
  • 源码分析 EventLoopGroup bossGroup = new NioEventLoopGroup(1);

    • 调用NioEventLoopGroup(int nThreads)构造器创建一个内部有一个线程池(注意EventLoopGroup下的EventLoop中都是单线程的线程池)

    • 其内部会调用到MultithreadEventLoopGroup(int nThreads, Executor executor, Object… args)构造器,此构造器内部会通过判断入参nThreads是否为0决定EventLoopGroup的线程数,如果nThread为0,则EventLoopGroup 的线程数会是默认线程数,默认线程数会在MultithreadEventLoopGroup类加载的时候,通过其静态代码块初始化,具体逻辑是,判断1,或者系统配置的参数io.netty.eventLoopThreads或者CPU核心数 * 2,这三者的最大值

      • public abstract class MultithreadEventLoopGroup extends MultithreadEventExecutorGroup implements EventLoopGroup {
        
            private static final InternalLogger logger = InternalLoggerFactory.getInstance(MultithreadEventLoopGroup.class);
        
            private static final int DEFAULT_EVENT_LOOP_THREADS;
        
            static {
                DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(
                        "io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));
        
                if (logger.isDebugEnabled()) {
                    logger.debug("-Dio.netty.eventLoopThreads: {}", DEFAULT_EVENT_LOOP_THREADS);
                }
            }
        
    • 接下去会调用到protected MultithreadEventExecutorGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory, Object… args) 构造器,这个构造器是真正的EventLoopGroup的初始化逻辑。无论是bossGroup还是WorkerGroup最终都会由这个构造器初始化

      • protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
                                                EventExecutorChooserFactory chooserFactory, Object... args) {
            if (nThreads <= 0) {
                throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
            }
        
            if (executor == null) {
                executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
            }
        
            children = new EventExecutor[nThreads];
        
            for (int i = 0; i < nThreads; i ++) {
                boolean success = false;
                try {
                    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);
                    }
                }
            };
        
            for (EventExecutor e: children) {
                e.terminationFuture().addListener(terminationListener);
            }
        
            Set<EventExecutor> childrenSet = new LinkedHashSet<EventExecutor>(children.length);
            Collections.addAll(childrenSet, children);
            readonlyChildren = Collections.unmodifiableSet(childrenSet);
        }
        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值