山东大学Netty 启动过程源码剖析2021SC@SDUSC

2021SC@SDUSC

Netty 核心源码剖析

1基本说明

  1. 只有看过 Netty 源码,才能说是真的掌握了 Netty 框架。

  2. io.netty.example 包下,有很多 Netty 源码案例,可以用来分析

  3. 源码分析章节 是针对有 Java 项目经验,并且玩过框架源码的人员讲的,否则看起来会有相当的难度。

2 Netty 启动过程源码剖析

2.1 源码剖析目的

用源码分析的方式走一下 Netty (服务器)的启动过程,更好的理解 Netty 的整体 设计和运行机制。

2.2 源码剖析

说明:

  1. 源码需要剖析到 Netty 调用 doBind 方法(进行程序的监听), 追踪到 NioServerSocketChannel 的 doBind
  2. 并且要 Debug 程序到 NioEventLoop 类 (事件循环)的 run 代码 ,无限循环,在服务器端运行。

在这里插入图片描述

2.3源码剖析过程

EchoServer

/*
 * 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.shandonguniversity.netty.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();
        }
    }
}

说明:

  1. 先看启动类:main 方法中,首先创建了关于 SSL 的配置类。
  2. 重点分析下 创建了两个 EventLoopGroup 对象:
    EventLoopGroup bossGroup = new NioEventLoopGroup(1);
    EventLoopGroup workerGroup = new NioEventLoopGroup();

(1) 这两个对象是整个 Netty 的核心对象,可以说,整个 Netty 的运作都依赖于他们。bossGroup 用于接受Tcp 请求,他会将请求交给 workerGroup ,workerGroup 会获取到真正的连接,然后和连接进行通信,比如读写解码编码等操作。
(2) EventLoopGroup 是 事件循环组(线程组) 含有多个 EventLoop, 可以注册 channel ,用于在事件循环中去进行选择(和选择器相关)。[debug 看一下]
workerGroup下有8个子线程。每个都是NioEventLoop.
在这里插入图片描述

(3)new NioEventLoopGroup(1); 这个 1 表示 bossGroup 事件组有 1 个线程你可以指定, 如果 new NioEventLoopGroup() 会含有默认个线程 cpu 核数*2, 即可以充分的利用多核的优势,【可以 dubug 一下】
DEFAULT_EVENT_LOOP_THREADS =Math.max(1,SystemPropertyUtil.getInt(“io.netty.eventLoopThreads”, NettyRuntime.availableProcessors() * 2));

会创建 EventExecutor 数组 children = new EventExecutor[nThreads]; //debug 一下
每个元素的类型就是 NIOEventLoop, NIOEventLoop 实现了 EventLoop 接口 和 Executor 接口try 块中创建了一个 ServerBootstrap 对象,他是一个引导类,用于启动服务器和引导整个程序的初始化(看下源码 allows easy bootstrap of {@link ServerChannel} )。它和 ServerChannel 关联, 而 ServerChannel 继承了 Channel,有一些方法 remoteAddress 等 [可以 Debug 下]
随后,变量 b 调用了 group 方法将两个 group 放入了自己的字段中,用于后期引导使用【debug 下 group 方法 】
在这里插入图片描述

(4)然后添加了一个 channel , 其中参数一个 Class 对象, 引导类将通过这个 Class 对象反射创建ChannelFactory。然后添加了一些 TCP 的参数。[说明:Channel 的创建在bind 方法,可以 Debug 下 bind ,会找到 channel=channelFactory.newChannel(); ]
(5)再添加了一个服务器专属的日志处理器 handler。
(6)再添加一个 SocketChannel(不是 ServerSocketChannel)的 handler。
(7)然后绑定端口并阻塞至连接成功。
(8)最后 main 线程阻塞等待关闭。
(9)finally 块中的代码将在服务器关闭时优雅关闭所有资源

//服务器端处理器源码

EchoServerHandler

/*
 * 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.shandonguniversity.netty.source.echo;

import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

/**
 * Handler implementation for the echo server.
 */
@Sharable
public class EchoServerHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        ctx.write(msg);
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        super.handlerAdded(ctx);
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        super.handlerRemoved(ctx);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        // Close the connection when an exception is raised.
        cause.printStackTrace();
        ctx.close();
    }
}

说明:

  1. 这是一个普通的处理器类,用于处理客户端发送来的消息,在我们这里,我们简单的解析出客户端传过来的内容,然后打印,最后发送字符串给客户端。
  2. 大致讲解了我们的 demo 源码的作用。后面的 debug 的时候会详细

分析 EventLoopGroup 的过程

2.1构造器方法
public NioEventLoopGroup(int nThreads) {
this(nThreads, (Executor) null);

}
2.2上面的 this(nThreads, (Executor) null);  调用构造器 (通过 alt+d 看即可) public NioEventLoopGroup(int nThreads, Executor executor) {
this(nThreads, executor, SelectorProvider.provider());
}
2.3上面的 this(nThreads, executor, SelectorProvider.provider());  调用下面构造器
public NioEventLoopGroup(
int nThreads, Executor executor, final SelectorProvider selectorProvider) { this(nThreads, executor, selectorProvider, DefaultSelectStrategyFactory.INSTANCE);
}
2.4上面的 this ()...调用构造器(alt+d)
public NioEventLoopGroup(int nThreads, Executor executor, final SelectorProvider selectorProvider,
final SelectStrategyFactory selectStrategyFactory) {
super(nThreads, executor, selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject());
}
2.5上面的 super() ..  的方法 是父类: MultithreadEventLoopGroup
protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) { super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
}
2.6追踪到源码 抽象类 MultithreadEventExecutorGroup 的构造器方法 MultithreadEventExecutorGroup 才是NioEventLoopGroup 真正的构造方法, 这里可以看成是一个模板方法,使用了设计模式的模板模式(可看我录制视频), 所以,我们就需要好好分析 MultithreadEventExecutorGroup 方法了
2.7分 析 MultithreadEventExecutorGroup
	参数说明:
@param nThreads	使用的线程数,默认为 core *2 [可以追踪源码]
@param executor	执行器:如果传入 null,则采用 Netty 默认的线程工厂和默认的执行器 ThreadPerTaskExecutor	

@param chooserFactory		单例 new DefaultEventExecutorChooserFactory() @param args	args 在创建执行器的时候传入固定参数
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 {

// 创 建 new 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) {
参数说明:
@param nThreads	使用的线程数,默认为 core *2 [可以追踪源码]
@param executor	执行器:如果传入 null,则采用 Netty 默认的线程工厂和默认的执行器 ThreadPerTaskExecutor	
@param chooserFactory 单例 new DefaultEventExecutorChooserFactory() 
@param args	args 在创建执行器的时候传入固定参数
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 {

// 创 建 new 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);	
	}	
	}	
	};	
	//为每一个单例线程池添加一个关闭监听器	
	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. 如果 executor 是 null,创建一个默认的 ThreadPerTaskExecutor,使用 Netty 默认的线程工厂。
  2. 根据传入的线程数(CPU*2)创建一个线程池(单例线程池)数组。
  3. 循环填充数组中的元素。如果异常,则关闭所有的单例线程池。
  4. 根据线程选择工厂创建一个 线程选择器。
  5. 为每一个单例线程池添加一个关闭监听器。
  6. 将所有的单例线程池添加到一个 HashSet 中。

3.ServerBootstrap 创建和构造过程
3.1ServerBootstrap 是个空构造,但是有默认的成员变量
	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;	

3.2 分析一下 ServerBootstrap 基本使用情况
	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());
}
});
说明:
1) 链式调用:group 方法,将 boss 和 worker 传入,boss 赋值给 parentGroup 属性,worker 赋值给 childGroup属性	
2)channel 方法传入 NioServerSocketChannel class 对象。会根据这个 class 创建 channel 对象。
3)option 方法传入 TCP 参数,放在一个 LinkedHashMap中。
4)handler 方法传入一个 handler  中,这个 hanlder 只专属于 ServerSocketChannel 而不是 SocketChannel
5)childHandler 传入一个 hanlder ,这个 handler 将会在每个客户端连接的时候调用。供 SocketChannel  使
用	

4.绑定端口的分析
4.1服务器就是在这个 bind 方法里启动完成的
4.2bind 方法代码, 追踪到 创建了一个端口对象,并做了一些空判断, 核心代码 doBind,我们看看
public ChannelFuture bind(SocketAddress localAddress) {
validate();
if (localAddress == null) {
throw new NullPointerException("localAddress");
}
return doBind(localAddress);
}



4.3doBind 源码剖析, 核心是两个方法 initAndRegister 和	doBind0
	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;
}
}	

4.4 分析说明 initAndRegister
	

final ChannelFuture initAndRegister() { Channel channel = null;
try {
// 说明: channelFactory.newChannel() 方法 的作用 通过 ServerBootstrap 的通道工厂反射创建一个
NioServerSocketChannel, 具体追踪源码可以得到下面结论

(1)通过 NIO 的 SelectorProvider  的 openServerSocketChannel 方法得到 JDK 的 channel。目的是让 Netty  包装 JDK 的 channel。
(2)创建了一个唯一的 ChannelId,创建了一个 NioMessageUnsafe,用于操作消息,创建了一个 DefaultChannelPipeline 管道,是个双向链表结构,用于过滤所有的进出的消息。
(3)创建了一个 NioServerSocketChannelConfig 对象,用于对外展示一些配置。
channel = channelFactory.newChannel();//NioServerSocketChannel
//说明:init 初始化这个 NioServerSocketChannel, 具体追踪源码可以得到如下结论


(1) init 方法,这是个抽象方法(AbstractBootstrap 类的),由 ServerBootstrap 实现(可以追一下源码 //setChannelOptions(channel, options, logger);)。
(2)设置 NioServerSocketChannel  的 TCP 属性。
(3)由于 LinkedHashMap 是非线程安全的,使用同步进行处理。
(4)NioServerSocketChannelChannelPipeline 添加 ChannelInitializer 处 理 器 。
(5)可以看出, init 的方法的核心作用在和 ChannelPipeline 相关。
(6)NioServerSocketChannel 的初始化过程中,我们知道,pipeline 是一个双向链表,并且,他本身就初始化了 head 和 tail,这里调用了他的  addLast  方法,也就是将整个  handler  插入到  tail  的前面,因为 tail 永远会在后面,需要做一些系统的固定工作。
init(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);
}
ChannelFuture regFuture = config().group().register(channel); if (regFuture.cause() != null) {
if (channel.isRegistered()) { channel.close();
} else {
channel.unsafe().closeForcibly();

}
}

return regFuture;

	}
说明:
1)基本说明: initAndRegister() 初始化 NioServerSocketChannel 通道并注册各个 handler,返回一个 future
2)通过 ServerBootstrap  的通道工厂反射创建一个 NioServerSocketChannel3)init 初始化这个 NioServerSocketChannel4)config().group().register(channel) 通过 ServerBootstrap 的 bossGroup 注册 NioServerSocketChannel5)最后,返回这个异步执行的占位符即 regFuture。	

4.5 init 方法 会调用 addLast,  现在进入到 addLast 方法内查看
	@Override
public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) { final AbstractChannelHandlerContext newCtx;
synchronized (this) { checkMultiplicity(handler);
newCtx = newContext(group, filterName(name, handler), handler); addLast0(newCtx);
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); return this;
}
说明:
1)addLast 方法,在 DefaultChannelPipeline 类中
2)addLast 方法这就是 pipeline 方法的核心
3)检查该 handler 是否符合标准。
4)创 建 一 个 AbstractChannelHandlerContext 对 象 , 这 里 说 一 下 , ChannelHandlerContext 对 象 是ChannelHandlerChannelPipeline 之间的关联, 每当有 ChannelHandler 添加到 Pipeline 中时,都会创建ContextContext 的主要功能是管理他所关联的 Handler  和同一个 Pipeline 中的其他 Handler 之间的交互。
5)Context 添加到链表中。也就是追加到 tail  节点的前面。
6)最后,同步或者异步或者晚点异步的调用 callHandlerAdded0 方法	

4.6 前面说了 dobind 方法有 2 个重要的步骤,initAndRegister 说完,接下来看 doBind0 方法,  代码如下
	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()) {	
	//bind 方法这里下断点,这里下断点,来玩!!	
	channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);	
	} else {	
	promise.setFailure(regFuture.cause());	
	}	
	}	
	});	
	}	
	说明:	
	1) 该方法的参数为 initAndRegister 的 future,NioServerSocketChannel,端口地址,NioServerSocketChannel 的	
	promise	
	2) 这里就可以根据前面下的断点,一直 debug:	
		将调用 LoggingHandler 的 invokeBind  方法,  最后会追到
//DefaultChannelPipeline 类的 bind
//然后进入到 unsafe.bind 方法 debug ,  注意要追踪到
// unsafe.bind , 要 debug 第二圈的时候,才能看到.
@Override public void bind(
ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise)
throws Exception {		

		unsafe.bind(localAddress, promise);		
		}		
		继续追踪 AbstractChannelpublic final void bind(final SocketAddress localAddress, final ChannelPromise promise) {		
		//....		
		
try {		
		//!!!!小红旗 可以看到,这里最终的方法就是 doBind 方法,执行成功后,执行通道的		
		fireChannelActive 方法,告诉所有的 handler,已经成功绑定。		
		doBind(localAddress);//		
		} catch (Throwable t) {		
		safeSetFailure(promise, t);		
		closeIfClosed();		
		return;		
		}		
		}		
	
3) 最终 doBind 就会追踪到 NioServerSocketChannel 的 doBind, 说明 Netty 底层使用的是 Nio @Override
protected void doBind(SocketAddress localAddress) throws Exception { if (PlatformDependent.javaVersion() >= 7) {
javaChannel().bind(localAddress, config.getBacklog());
} else {
javaChannel().socket().bind(localAddress, config.getBacklog());
}
}	



Netty 启动过程梳理

  1. 创建 2 个 EventLoopGroup 线程池数组。数组默认大小 CPU*2,方便 chooser 选择线程池时提高性能

  2. BootStrap 将 boss 设置为 group 属性,将 worker 设置为 childer 属性

  3. 通过 bind 方法启动,内部重要方法为 initAndRegister 和 dobind 方法

  4. initAndRegister 方法会反射创建 NioServerSocketChannel 及其相关的 NIO 的对象, pipeline ,unsafe,同时也为 pipeline 初始了 head 节点和 tail 节点。

  5. 在 register0 方法成功以后调用在 dobind 方法中调用 doBind0 方法,该方法会 调用 NioServerSocketChannel的 doBind 方法对 JDK 的 channel 和端口进行绑定,完成 Netty 服务器的所有启动,并开始监听连接事件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值