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