NettyServer端源码
根据代码演示分析
public static void main(String[] args) throws InterruptedException {
EventLoopGroup parentGroup = new NioEventLoopGroup();
EventLoopGroup childGroup = new NioEventLoopGroup();
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(parentGroup, childGroup)
// 指定要创建Channel类型
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
// 获取channel中的Pipeline
ChannelPipeline pipeline = ch.pipeline();
// StringDecoder:字符串解码器,将Channel中的ByteBuf数据解码为String
pipeline.addLast(new StringDecoder());
// StringEncoder:字符串编码器,将String编码为将要发送到Channel中的ByteBuf
pipeline.addLast(new StringEncoder());
pipeline.addLast(new SomeServerHandler());
}
});
ChannelFuture future = bootstrap.bind(8080).sync();
System.out.println("服务器已启动");
future.channel().closeFuture().sync();
} finally {
parentGroup.shutdownGracefully();
childGroup.shutdownGracefully();
}
}
4.1.36源码从绑定开始分析:
Netty服务端启动
创建指定channel
在执行bind之前,先执行了channel(NioServerSocketChannel.class) ,先创建指定的channel
【AbstractBootstrap.class】
public B channel(Class<? extends C> channelClass) {
if (channelClass == null) {
throw new NullPointerException("channelClass");
}
// 返回一个channelFactory
return channelFactory(new ReflectiveChannelFactory<C>(channelClass));
}
public ReflectiveChannelFactory(Class<? extends T> clazz) {
ObjectUtil.checkNotNull(clazz, "clazz");
try {
// 初始化NioServerSocketChannel的构造器
this.constructor = clazz.getConstructor();
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Class " + StringUtil.simpleClassName(clazz) +
" does not have a public non-arg constructor", e);
}
}
执行bind流程
【AbstractBootstrap】#bind 绑定
|-- doBind
|--【AbstractBootstrap】# initAndRegister #创建、初始化channel,并将其注册到Selector
|-- channelFactory.newChannel(); #创建一个channel
|-- constructor.newInstance(); #使用反射机制,调用其无参构造器,创建channel
|-- #这里创造的channel 最终调用NioServerSocketChannel的无参构造函数
|-- NioServerSocketChannel() #进入无参构造器
|-- newSocket()
|-- provider.openServerSocketChannel();#通过全局性的provider,创建一个原生的NIO的channel
|--NioServerSocketChannel(ServerSocketChannel channel)#NioServerSocketChannel实际上是对原生NIO的channel的封装
|-- super AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) # readInterestOp传入的是 SelectionKey.OP_ACCEPT调用父类
|-- AbstractChannel(Channel parent)
|-- newId()#为Netty的channel生成id
|-- newUnsafe()#底层操作对象
|-- pipeline = newChannelPipeline()#创建当前channel所绑定的channelPipeline
|-- ch.configureBlocking(false);#指定channel为非阻塞
|-- config = new NioServerSocketChannelConfig(this, javaChannel().socket());#获取channel的配置对象,用于设置一些传输的属性,例如:setOptions
|--【ServerBootstrap】#init(channel) 初始化channel
|-- #处理options0和attr设置属性
|-- p.addLast(new ChannelInitializer<Channel>() #ChannelInitializer是一个处理器,其存在的意义是,为pipeline添加其它处理器
|-- ch.eventLoop().execute() # ch.eventLoop()是获取到当前channel所绑定的evenLoop 然后再使用该eventLoop所绑定的线程来执行指定的任务
|-- pipeline.addLast(new ServerBootstrapAcceptor(
ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));#向pipeline中添加ServerBootstrapAcceptor处理器,该处理器用于处理client的连接
|-- channelRead(ChannelHandlerContext ctx, Object msg) #当客户端连接请求过来会执行channelRead方法
|-- child.pipeline().addLast(childHandler);#对用于处理client 读写请求的子channel设置handler,以及添加到对应的selector中
|-- childGroup.register(child).addListener #将当前子channel注册到selector
|-- #config().group().register(channel);#将当前channel注册给selector
|--【MultithreadEventLoopGroup】#register
|-- next().register(channel);#从parentGroup中根据算法选择一个eventLoop来完成注册
|-- 【GenericEventExecutorChooser】#next executors[Math.abs(idx.getAndIncrement() % executors.length)];
|-- 【PowerOfTwoEventExecutorChooser】#next executors[idx.getAndIncrement() & executors.length - 1]; 轮询 若a是一个2的整数次幂,则 b & (a-1) 与 b % a 是等价的 但 b & (a-1) 的效率要更高
|--【AbstractChannel】#register
|-- eventLoop.inEventLoop()#判断当前正在执行的线程是否是当前eventLoop所绑定的线程
|-- 是 进入register0()
|-- 【AbstractNioChannel】#doRegister();#完成注册 其实netty的channel的注册,本质上是原生的nio的channel的注册
|-- pipeline.invokeHandlerAddedIfNeeded(); #触发handlerAdded()方法的执行
|-- pipeline.fireChannelRegistered(); #触发channelRegistered()方法的执行
|-- pipeline.fireChannelActive(); #若当前channel是激活状态,且是第一次注册,则触发channelActive()的执行
|-- 否 #当前线程不是eventLoop绑定线程,则首先会创建一个线程,然后使用这个新创建的eventLoop线程来完成注册
|--regFuture.channel();#从异步结果中获取channel
|--#获取异步操作过程中发生的异常
|--regFuture.isDone() #判断当前异步操作是否完成:或者是成功,或者是异常
|--成功
|-- ChannelPromise promise = channel.newPromise();#创建一个可修改的异步结果对象channelFuture
|-- 异步操作未完成
|-- regFuture.addListener#为异步操作添加监听器
|--operationComplete #当异步操作完成(成功,异常),就会触发该方法的执行
|-- 如果有异常修改异步结果为失败
|-- doBind0()#绑定端口号
|--【AbstractUnsafe】#bind
|--【NioServerSocketChannel】#doBind
private ChannelFuture doBind(final SocketAddress localAddress) {
// 创建、初始化channel,并将其注册到Selector
final ChannelFuture regFuture = initAndRegister();
// 从异步结果中获取channel
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.
// 创建一个可修改的异步结果对象channelFuture
ChannelPromise promise = channel.newPromise();
// 绑定端口号
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;
}
}
【NioServerSocketChannel】#doBind
@Override
protected void doBind(SocketAddress localAddress) throws Exception {
if (PlatformDependent.javaVersion() >= 7) {
javaChannel().bind(localAddress, config.getBacklog());
} else {
javaChannel().socket().bind(localAddress, config.getBacklog());
}
}
注册流程
initAndRegister 流程
|--【AbstractBootstrap】# initAndRegister #创建、初始化channel,并将其注册到Selector
|-- channelFactory.newChannel(); #创建一个channel
|-- constructor.newInstance(); #使用反射机制,调用其无参构造器,创建channel
|-- #这里创造的channel 最终调用NioServerSocketChannel的无参构造函数
|-- NioServerSocketChannel() #进入无参构造器
|-- newSocket()
|-- provider.openServerSocketChannel();#通过全局性的provider,创建一个原生的NIO的channel
|--NioServerSocketChannel(ServerSocketChannel channel)#NioServerSocketChannel实际上是对原生NIO的channel的封装
|-- super AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) # readInterestOp传入的是 SelectionKey.OP_ACCEPT调用父类
|-- AbstractChannel(Channel parent)
|-- newId()#为Netty的channel生成id
|-- newUnsafe()#底层操作对象
|-- pipeline = newChannelPipeline()#创建当前channel所绑定的channelPipeline
|-- ch.configureBlocking(false);#指定channel为非阻塞
|-- config = new NioServerSocketChannelConfig(this, javaChannel().socket());#获取channel的配置对象,用于设置一些传输的属性,例如:setOptions
|--【ServerBootstrap】#init(channel) 初始化channel
|-- #处理options0和attr设置属性
|-- p.addLast(new ChannelInitializer<Channel>() #ChannelInitializer是一个处理器,其存在的意义是,为pipeline添加其它处理器
|-- ch.eventLoop().execute() # ch.eventLoop()是获取到当前channel所绑定的evenLoop 然后再使用该eventLoop所绑定的线程来执行指定的任务
|-- pipeline.addLast(new ServerBootstrapAcceptor(
ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));#向pipeline中添加ServerBootstrapAcceptor处理器,该处理器用于处理client的连接
|-- channelRead(ChannelHandlerContext ctx, Object msg) #当客户端连接请求过来会执行channelRead方法
|-- child.pipeline().addLast(childHandler);#对用于处理client 读写请求的子channel设置handler,以及添加到对应的selector中
|-- childGroup.register(child).addListener #将当前子channel注册到selector
|-- #config().group().register(channel);#将当前channel注册给selector
|--【MultithreadEventLoopGroup】#register
|-- next().register(channel);#从parentGroup中根据算法选择一个eventLoop来完成注册
|-- 【GenericEventExecutorChooser】#next executors[Math.abs(idx.getAndIncrement() % executors.length)];
|-- 【PowerOfTwoEventExecutorChooser】#next executors[idx.getAndIncrement() & executors.length - 1]; 轮询 若a是一个2的整数次幂,则 b & (a-1) 与 b % a 是等价的 但 b & (a-1) 的效率要更高
|--【AbstractChannel】#register
|-- eventLoop.inEventLoop()#判断当前正在执行的线程是否是当前eventLoop所绑定的线程
|-- 是 进入register0()
|-- 【AbstractNioChannel】#doRegister();#完成注册 其实netty的channel的注册,本质上是原生的nio的channel的注册
|-- pipeline.invokeHandlerAddedIfNeeded(); #触发handlerAdded()方法的执行
|-- pipeline.fireChannelRegistered(); #触发channelRegistered()方法的执行
|-- pipeline.fireChannelActive(); #若当前channel是激活状态,且是第一次注册,则触发channelActive()的执行
|-- 否 #当前线程不是eventLoop绑定线程,则首先会创建一个线程,然后使用这个新创建的eventLoop线程来完成注册
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
// 创建一个channel
channel = channelFactory.newChannel();
// 初始化channel
init(channel);
} catch (Throwable t) {
if (channel != null) {
// channel can be null if newChannel crashed (eg SocketException("too many open files"))
channel.unsafe().closeForcibly();
// as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
}
// as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
return new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE).setFailure(t);
}
// 将当前channel注册给selector
ChannelFuture regFuture = config().group().register(channel);
if (regFuture.cause() != null) {
if (channel.isRegistered()) {
channel.close();
} else {
channel.unsafe().closeForcibly();
}
}
return regFuture;
}
channelFactory.newChannel()流程
创建channel
public T newChannel() {
try {
// 使用反射机制,调用其无参构造器,创建channel
return constructor.newInstance();
} catch (Throwable t) {
throw new ChannelException("Unable to create Channel from class " + constructor.getDeclaringClass(), t);
}
}
最终调用NioServerSocketChannel的无参构造函数
// 获取到一个全局性的provider
private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();
【NioServerSocketChannel】
public NioServerSocketChannel() {
// 我们Netty的channel实际上是对原生的NIO的channel的封装
this(newSocket(DEFAULT_SELECTOR_PROVIDER));
}
// netty最终调用了 jdk原生nio,
private static ServerSocketChannel newSocket(SelectorProvider provider) {
try {
// 通过全局性的provider,创建一个原生的NIO的channel
return provider.openServerSocketChannel();
} catch (IOException e) {
throw new ChannelException(
"Failed to open a server socket.", e);
}
}
【AbstractNioChannel】
protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
super(parent);
this.ch = ch;
this.readInterestOp = readInterestOp;
try {
// 指定channel为非阻塞
ch.configureBlocking(false);
} catch (IOException e) {
try {
ch.close();
} catch (IOException e2) {
if (logger.isWarnEnabled()) {
logger.warn(
"Failed to close a partially initialized socket.", e2);
}
}
throw new ChannelException("Failed to enter non-blocking mode.", e);
}
}
protected AbstractChannel(Channel parent) {
this.parent = parent;
// 为Netty的channel生成id
id = newId();
// 底层操作对象
unsafe = newUnsafe();
// 创建当前channel所绑定的channelPipeline
pipeline = newChannelPipeline();
}
初始化channel
【ServerBootstrap】#init
@Override
void init(Channel channel) throws Exception {
// 处理bootstrap中的option设置属性
final Map<ChannelOption<?>, Object> options = options0();
synchronized (options) {
setChannelOptions(channel, options, logger);
}
// 处理bootstrap中的attr设置属性
final Map<AttributeKey<?>, Object> attrs = attrs0();
synchronized (attrs) {
// 将bootstrap中设置的所有attr属性配置给channel
for (Entry<AttributeKey<?>, Object> e: attrs.entrySet()) {
@SuppressWarnings("unchecked")
AttributeKey<Object> key = (AttributeKey<Object>) e.getKey();
channel.attr(key).set(e.getValue());
}
}
// 向pipeline中添加处理器
ChannelPipeline p = channel.pipeline();
// 获取bootstrap中设置的所有child开头的属性
final EventLoopGroup currentChildGroup = childGroup;
final ChannelHandler currentChildHandler = childHandler;
final Entry<ChannelOption<?>, Object>[] currentChildOptions;
final Entry<AttributeKey<?>, Object>[] currentChildAttrs;
synchronized (childOptions) {
currentChildOptions = childOptions.entrySet().toArray(newOptionArray(0));
}
synchronized (childAttrs) {
currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(0));
}
// ChannelInitializer是一个处理器,其存在的意义是,为pipeline添加其它处理器
p.addLast(new ChannelInitializer<Channel>() {
@Override
public void initChannel(final Channel ch) throws Exception {
final ChannelPipeline pipeline = ch.pipeline();
// 获取bootstrap中配置的handler()
ChannelHandler handler = config.handler();
if (handler != null) {
pipeline.addLast(handler);
}
// ch.eventLoop()是获取到当前channel所绑定的evenLoop
// 然后再使用该eventLoop所绑定的线程来执行指定的任务
ch.eventLoop().execute(new Runnable() {
@Override
public void run() {
// 向pipeline中添加ServerBootstrapAcceptor处理器
// 该处理器用于处理client的连接
pipeline.addLast(new ServerBootstrapAcceptor(
ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}
});
}
});
}
static void setChannelOptions(
Channel channel, Map<ChannelOption<?>, Object> options, InternalLogger logger) {
// 遍历通过bootstrap设置的所有option
for (Map.Entry<ChannelOption<?>, Object> e: options.entrySet()) {
setChannelOption(channel, e.getKey(), e.getValue(), logger);
}
}
ServerBootstrapAcceptor.class
ServerBootstrapAcceptor(
final Channel channel, EventLoopGroup childGroup, ChannelHandler childHandler,
Entry<ChannelOption<?>, Object>[] childOptions, Entry<AttributeKey<?>, Object>[] childAttrs) {
this.childGroup = childGroup;
this.childHandler = childHandler;
this.childOptions = childOptions;
this.childAttrs = childAttrs;
// Task which is scheduled to re-enable auto-read.
// It's important to create this Runnable before we try to submit it as otherwise the URLClassLoader may
// not be able to load the class because of the file limit it already reached.
//
// See https://github.com/netty/netty/issues/1328
enableAutoReadTask = new Runnable() {
@Override
public void run() {
channel.config().setAutoRead(true);
}
};
}
// 当client发送来连接请求时,会触发channelRead()方法的执行
@Override
@SuppressWarnings("unchecked")
public void channelRead(ChannelHandlerContext ctx, Object msg) {
// 注意,这里client发送来的就是连接当前Server的子channel
final Channel child = (Channel) msg;
// 初始化这个子channel
// 对用于处理client 读写请求的子channel设置handler,以及添加到对应的selector中
child.pipeline().addLast(childHandler);
setChannelOptions(child, childOptions, logger);
for (Entry<AttributeKey<?>, Object> e: childAttrs) {
child.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());
}
try {
// 将当前子channel注册到selector
childGroup.register(child).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
forceClose(child, future.cause());
}
}
});
} catch (Throwable t) {
forceClose(child, t);
}
}
channel注册到selector上
ChannelFuture regFuture = config().group().register(channel); 将当前channel注册给selector,这里指的是parentGroup
【MultithreadEventLoopGroup.class】
@Override
public ChannelFuture register(Channel channel) {
// 从parentGroup中根据算法选择一个eventLoop来完成注册
return next().register(channel);
}
【AbstractChannel.class】中的【AbstractUnsafe.class】#register
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与eventLoop的绑定
AbstractChannel.this.eventLoop = eventLoop;
// 判断当前正在执行的线程是否是当前eventLoop所绑定的线程
if (eventLoop.inEventLoop()) {
// 若当前线程是eventLoop绑定线程,则直接让这个线程来完成注册操作
register0(promise);
} else {
// 当前线程不是eventLoop绑定线程,则首先会创建一个线程,
// 然后使用这个新创建的eventLoop线程来完成注册
try {
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);
}
}
}
private void register0(ChannelPromise promise) {
try {
// check if the channel is still open as it could be closed in the mean time when the register
// call was outside of the eventLoop
if (!promise.setUncancellable() || !ensureOpen(promise)) {
return;
}
boolean firstRegistration = neverRegistered;
// 完成注册
doRegister();
// 修改状态值
neverRegistered = false;
registered = true;
// Ensure we call handlerAdded(...) before we actually notify the promise. This is needed as the
// user may already fire events through the pipeline in the ChannelFutureListener.
// 触发handlerAdded()方法的执行
pipeline.invokeHandlerAddedIfNeeded();
safeSetSuccess(promise);
// 触发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.
// 若当前channel是激活状态,且是第一次注册,
// 则触发channelActive()的执行
if (isActive()) {
if (firstRegistration) {
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);
}
}
doRegister() 跟进去
【AbstractNioChannel】#doRegister
protected void doRegister() throws Exception {
boolean selected = false;
for (;;) {
try {
// 其实netty的channel的注册,本质上是原生的nio的channel的注册
//eventLoop对应一个selector,从eventLoop中找到selector,将channel注册到eventLoop对应的selector上
selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
return;
} catch (CancelledKeyException e) {
if (!selected) {
// Force the Selector to select now as the "canceled" SelectionKey may still be
// cached and not removed because no Select.select(..) operation was called yet.
eventLoop().selectNow();
selected = true;
} else {
// We forced a select operation on the selector before but the SelectionKey is still cached
// for whatever reason. JDK bug ?
throw e;
}
}
}
}
在执行bind之前,先执行了channel(NioServerSocketChannel.class)
【AbstractBootstrap】#bind
|--dobind
|-- final ChannelFuture regFuture = initAndRegister(); 创建、初始化channel,并将其注册到selector
|-- channel = channelFactory.newChannel(); //创建一个channel
|--【ReflectiveChannelFactory】#newChannel
|--constructor.newInstance(); 使用反射机制 调用其无参构造器 在调用之前,这里其实就是先执行了NioServerSocketChannel.class 这个方法,创建了
NioEventLoop分析
NioEventLoopGroup与NioEventLoop
两个类都最后都继承自Executor。所以都是一个执行器
NioEventLoopGroup本身是个执行器(Executor),里面还包含了executor,可以调用execute,是线程池实现的execute
NioEventLoop本身是个执行器(Executor),里面还包含了executor,子executor里面又包含了线程,这个线程是总的executor绑定的factory创建的,可以调用execute,是线程实现的execute
EventLoop绑定的线程是在什么时候创建的?执行注册的时候创建的
EventLoop本身是exector,同时它也包含executor,所包含的executor会绑定一个线程,此线程负责处理selector返回就绪的任务请求
每个EventLoop都会有任务队列,任务队列放的是任务,任务是实现Runable接口的类,每个任务队列都会有一个线程与之绑定,所绑定的线程来执行任务队列里面的每一个任务
NioEventLoopGroup创建
new NioEventLoopGroup 跟进去
|-- MultithreadEventExecutorGroup()
|-- executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());# // 创建一个总executor,这个executor将来会为每一个EventLoop创建一个子executor, 然后再使用当前这个总executor所绑定的线程Factory为每个子executor再创建一个线程,与这个子executor绑定
|--newChild() # 创建每一个eventLoop实例,并初始化到相应的数组元素中
|-- new NioEventLoop()
|--super new SingleThreadEventExecutor()
|--this.executor = ThreadExecutorMap.apply(executor, this);#使用总的executor为当前eventLoop创建一个executor,EventLoop本身是exector,同时它也包含executor,所包含的executor会绑定一个线程, 此线程负责处理selector返回就绪的任务请求
|--chooser = chooserFactory.newChooser(children);#创建一个EventLoop数组元素的选择器
跳转到 MultithreadEventLoopGroup
private static final int DEFAULT_EVENT_LOOP_THREADS;
static {
// 该默认值为当前主机逻辑处理器数量的2倍
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 MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {
super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, 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,这个executor将来会为每一个EventLoop创建一个子executor,
// 然后再使用当前这个总executor所绑定的线程Factory为每个子executor再创建一个线程
// 与这个子executor绑定
executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
}
// 使用一个数组来存放当前group中所包含的eventLoop
children = new EventExecutor[nThreads];
for (int i = 0; i < nThreads; i ++) {
boolean success = false;
try {
// 创建每一个eventLoop实例,并初始化到相应的数组元素中
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;
}
}
}
}
}
// 创建一个EventLoop数组元素的选择器
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);
}
newDefaultThreadFactory()跟进去
【DefaultThreadFactory.class】
public DefaultThreadFactory(String poolName, boolean daemon, int priority, ThreadGroup threadGroup) {
if (poolName == null) {
throw new NullPointerException("poolName");
}
if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) {
throw new IllegalArgumentException(
"priority: " + priority + " (expected: Thread.MIN_PRIORITY <= priority <= Thread.MAX_PRIORITY)");
}
// 最终获取到的prefix的值为 nioEventLoopGroup-线程池id-
prefix = poolName + '-' + poolId.incrementAndGet() + '-';
this.daemon = daemon;
this.priority = priority;
this.threadGroup = threadGroup;
}
newChild(executor, args); 跟进去
【NioEventLoopGroup】#newChild
@Override
protected EventLoop newChild(Executor executor, Object... args) throws Exception {
return new NioEventLoop(this, executor, (SelectorProvider) args[0],
((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2]);
}
调用NioEventLoop 构造器
【NioEventLoop】
NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider,
SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler) {
super(parent, executor, false, DEFAULT_MAX_PENDING_TASKS, rejectedExecutionHandler);
if (selectorProvider == null) {
throw new NullPointerException("selectorProvider");
}
if (strategy == null) {
throw new NullPointerException("selectStrategy");
}
provider = selectorProvider;
// 创建一个Selector元组
final SelectorTuple selectorTuple = openSelector();
selector = selectorTuple.selector;
unwrappedSelector = selectorTuple.unwrappedSelector;
selectStrategy = strategy;
}
super 跟进去调用SingleThreadEventLoop 构造器
【SingleThreadEventLoop】
protected SingleThreadEventLoop(EventLoopGroup parent, Executor executor,
boolean addTaskWakesUp, int maxPendingTasks,
RejectedExecutionHandler rejectedExecutionHandler) {
super(parent, executor, addTaskWakesUp, maxPendingTasks, rejectedExecutionHandler);
// 创建一个尾部任务队列,收尾任务存放在这里
tailTasks = newTaskQueue(maxPendingTasks);
}
super 跟进去调用SingleThreadEventExecutor构造器
protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor,
boolean addTaskWakesUp, int maxPendingTasks,
RejectedExecutionHandler rejectedHandler) {
super(parent);
this.addTaskWakesUp = addTaskWakesUp;
this.maxPendingTasks = Math.max(16, maxPendingTasks);
// 使用总的executor为当前eventLoop创建一个executor this.executor是eventLoop中的executor,executor是总的
this.executor = ThreadExecutorMap.apply(executor, this);
// 创建一个任务队列
taskQueue = newTaskQueue(this.maxPendingTasks);
rejectedExecutionHandler = ObjectUtil.checkNotNull(rejectedHandler, "rejectedHandler");
}
ThreadExecutorMap.apply(executor, this);跟进去
【ThreadExecutorMap】
/**
*
* @param executor 总的executor
* @param eventExecutor 当前正在创建的eventLoop
* @return
* 线程套线程,相当于责任链 这时候才创建了个匿名的executor,这个new Executor现在不会执行,只有在任务开始的时候才会执行
*/
public static Executor apply(final Executor executor, final EventExecutor eventExecutor) {
ObjectUtil.checkNotNull(executor, "executor");
ObjectUtil.checkNotNull(eventExecutor, "eventExecutor");
return new Executor() {
@Override
public void execute(final Runnable command) {
// executor.execute()会使用这个总的executor所绑定的线程factory创建一个线程
executor.execute(apply(command, eventExecutor));
}
};
}
public static Runnable apply(final Runnable command, final EventExecutor eventExecutor) {
ObjectUtil.checkNotNull(command, "command");
ObjectUtil.checkNotNull(eventExecutor, "eventExecutor");
return new Runnable() {
@Override
public void run() {
// 为了保证线程安全,这里为当前线程指定其所关联的eventLoop
setCurrentEventExecutor(eventExecutor);
try {
// 真正任务的执行是在这里开始的
command.run();
} finally {
setCurrentEventExecutor(null);
}
}
};
}
有任务的时候就去执行上面那个匿名的executor
NioEventLoop添加任务
举例:register时候线程创建,其他的任务会直接放入队列中等待执行
【SingleThreadEventExecutor】#execute
|-- addTask(task);#将任务添加到taskQueue
|-- startThread();#创建并启动线程
|--doStartThread()#启动线程
|-- executor.execute #调用当前EventLoop所包含的executor(子executor)
|-- ThreadExecutorMap.apply# executor.execute 中的run方法 最终会调用ThreadExecutorMap.apply的执行run方法
|-- SingleThreadEventExecutor.this.run();#进行selector的选择,然后执行三类任务
|-- 【NioEventLoop】#run
|--selectStrategy.calculateStrategy(selectNowSupplier, hasTasks())#计算出选择selector策略
|-- SelectStrategy.SELECT: select(wakenUp.getAndSet(false));#若执行这里,说明当前任务队列中没有任务
|--processSelectedKeys();#2 处理就绪的IO
|--runAllTasks(ioTime * (100 - ioRatio) / ioRatio);#3 执行任务队列中的任务
// 判断当前正在执行的线程是否是当前eventLoop所绑定的线程
if (eventLoop.inEventLoop()) {
// 若当前线程是eventLoop绑定线程,则直接让这个线程来完成注册操作
register0(promise);
} else {
// 当前线程不是eventLoop绑定线程,则首先会创建一个线程,
// 然后使用这个新创建的eventLoop线程来完成注册
try {
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);
}
}
eventLoop.execute跟进去
【SingleThreadEventExecutor】#execute
@Override
public void execute(Runnable task) {
if (task == null) {
throw new NullPointerException("task");
}
// 若当前线程是当前EventLoop所绑定的线程,则返回true,否则返回false
boolean inEventLoop = inEventLoop();
// 将任务添加到taskQueue
addTask(task);
if (!inEventLoop) {
// 创建并启动线程
startThread();
if (isShutdown()) {
boolean reject = false;
try {
if (removeTask(task)) {
reject = true;
}
} catch (UnsupportedOperationException e) {
// The task queue does not support removal so the best thing we can do is to just move on and
// hope we will be able to pick-up the task before its completely terminated.
// In worst case we will log on termination.
}
if (reject) {
reject();
}
}
}
if (!addTaskWakesUp && wakesUpForTask(task)) {
wakeup(inEventLoop);
}
} startThread();
startThread();方法跟进去
private void startThread() {
if (state == ST_NOT_STARTED) {
// 通过CAS将状态修改为已启动
if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED)) {
try {
// 启动线程
doStartThread();
} catch (Throwable cause) {
STATE_UPDATER.set(this, ST_NOT_STARTED);
PlatformDependent.throwException(cause);
}
}
}
}
private void doStartThread() {
assert thread == null;
// 调用当前EventLoop所包含的executor(子executor)
executor.execute(new Runnable() {
@Override
public void run() {
thread = Thread.currentThread();
if (interrupted) {
thread.interrupt();
}
boolean success = false;
updateLastExecutionTime();
try {
// 进行selector的选择,然后执行三类任务
SingleThreadEventExecutor.this.run();
success = true;
} catch (Throwable t) {
logger.warn("Unexpected exception from an event executor: ", t);
} finally {
for (;;) {
int oldState = state;
if (oldState >= ST_SHUTTING_DOWN || STATE_UPDATER.compareAndSet(
SingleThreadEventExecutor.this, oldState, ST_SHUTTING_DOWN)) {
break;
}
}
// Check if confirmShutdown() was called at the end of the loop.
if (success && gracefulShutdownStartTime == 0) {
if (logger.isErrorEnabled()) {
logger.error("Buggy " + EventExecutor.class.getSimpleName() + " implementation; " +
SingleThreadEventExecutor.class.getSimpleName() + ".confirmShutdown() must " +
"be called before run() implementation terminates.");
}
}
try {
// Run all remaining tasks and shutdown hooks.
for (;;) {
if (confirmShutdown()) {
break;
}
}
} finally {
try {
cleanup();
} finally {
// Lets remove all FastThreadLocals for the Thread as we are about to terminate and notify
// the future. The user may block on the future and once it unblocks the JVM may terminate
// and start unloading classes.
// See https://github.com/netty/netty/issues/6596.
FastThreadLocal.removeAll();
STATE_UPDATER.set(SingleThreadEventExecutor.this, ST_TERMINATED);
threadLock.release();
if (!taskQueue.isEmpty()) {
if (logger.isWarnEnabled()) {
logger.warn("An event executor terminated with " +
"non-empty task queue (" + taskQueue.size() + ')');
}
}
terminationFuture.setSuccess(null);
}
}
}
}
});
}
// 调用当前EventLoop所包含的executor(子executor)
executor.execute(new Runnable()
这时候就会去调用刚才那个匿名创建的 Executor 进来
【ThreadExecutorMap】
/**
*
* @param executor 总的executor
* @param eventExecutor 当前正在创建的eventLoop
* @return
* 线程套线程,相当于责任链 这时候才创建了个匿名的executor,这个new Executor现在不会执行,只有在任务开始的时候才会执行
*/
public static Executor apply(final Executor executor, final EventExecutor eventExecutor) {
ObjectUtil.checkNotNull(executor, "executor");
ObjectUtil.checkNotNull(eventExecutor, "eventExecutor");
return new Executor() {
@Override
public void execute(final Runnable command) {
// executor.execute()会使用这个总的executor所绑定的线程factory创建一个线程
executor.execute(apply(command, eventExecutor));
}
};
}
最终会调用走到
【ThreadPerTaskExecutor】#execute
@Override
public void execute(Runnable command) {
// 这里会创建一个线程,并且启动这个线程,就是执行command的run()方法
threadFactory.newThread(command).start();
}
【DefaultThreadFactory】#newThread
@Override
public Thread newThread(Runnable r) {
// 创建一个线程,使用线程的名称为 nioEventLoopGroup-线程池id-线程id
Thread t = newThread(FastThreadLocalRunnable.wrap(r), prefix + nextId.incrementAndGet());
try {
if (t.isDaemon() != daemon) {
t.setDaemon(daemon);
}
if (t.getPriority() != priority) {
t.setPriority(priority);
}
} catch (Exception ignored) {
// Doesn't matter even if failed to set.
}
return t;
}
NioEventLoop任务执行
SingleThreadEventExecutor.this.run();
【NioEventLoop】#run
protected void run() {
// 永久循环
for (;;) {
try {
try {
// ------------------------- 1 selector选择 -------------------
// 计算出选择selector策略
switch (selectStrategy.calculateStrategy(selectNowSupplier, hasTasks())) {
case SelectStrategy.CONTINUE: // NioEventLoop不支持
continue;
case SelectStrategy.BUSY_WAIT: // Nio不支持
// fall-through to SELECT since the busy-wait is not supported with NIO
case SelectStrategy.SELECT: // NioEventLoop支持的唯一策略
// 若执行这里,说明当前任务队列中没有任务
select(wakenUp.getAndSet(false));
// 若当前线程刚被唤醒,selector立即将其选择的结果返回给我们
if (wakenUp.get()) {
selector.wakeup();
}
// fall through
default:
}
} catch (IOException e) {
// If we receive an IOException here its because the Selector is messed up. Let's rebuild
// the selector and retry. https://github.com/netty/netty/issues/8566
rebuildSelector0();
handleLoopException(e);
continue;
}
cancelledKeys = 0;
needsToSelectAgain = false;
// ioRatio用于控制IO处理与任务队列中任务的处理所占时间比例
final int ioRatio = this.ioRatio;
if (ioRatio == 100) {
try {
processSelectedKeys();
} finally {
// Ensure we always run tasks.
runAllTasks();
}
} else {
// ------------------------- 2 处理就绪的IO -------------------
// IO操作的开始时间
final long ioStartTime = System.nanoTime();
try {
processSelectedKeys();
} finally {
// ------------------------- 3 执行任务队列中的任务 -------------------
// Ensure we always run tasks.
// IO操作总用时
final long ioTime = System.nanoTime() - ioStartTime;
// ioTime * [(100 - ioRatio) / ioRatio]
runAllTasks(ioTime * (100 - ioRatio) / ioRatio);
}
}
} catch (Throwable t) {
handleLoopException(t);
}
// Always handle shutdown even if the loop processing threw an exception.
try {
if (isShuttingDown()) {
closeAll();
if (confirmShutdown()) {
return;
}
}
} catch (Throwable t) {
handleLoopException(t);
}
}
}
selectStrategy.calculateStrategy(selectNowSupplier, hasTasks()) 跟进去
先看下selectNowSupplier
private final IntSupplier selectNowSupplier = new IntSupplier() {
@Override
public int get() throws Exception {
// 非阻塞选择
return selectNow();
}
};
int selectNow() throws IOException {
try {
// 非阻塞选择
return selector.selectNow();
} finally {
// restore wakeup state if needed
// wakenUp为true,表示当前eventLoop所绑定的线程刚刚被唤醒
// wakenUp为false,表示当前eventLoop所绑定的线程即将被阻塞
if (wakenUp.get()) {
// 立即将选择的结果写入到当前eventLoop的集合
selector.wakeup();
}
}
}
【Si ngleThreadEventLoop】
@Override
protected boolean hasTasks() {
// 判断 taskQueue 或 tailTasks 任务队列是否为空
return super.hasTasks() || !tailTasks.isEmpty();
}
calculateStrategy跟进来
【DefaultSelectStrategy】#calculateStrategy
@Override
public int calculateStrategy(IntSupplier selectSupplier, boolean hasTasks) throws Exception {
// 若任务队列有任务,则马上进行非阻塞选择
return hasTasks ? selectSupplier.get() : SelectStrategy.SELECT;
}
select(wakenUp.getAndSet(false));跟进来,执行这里,说明当前任务队列中没有任务
private void select(boolean oldWakenUp) throws IOException {
Selector selector = this.selector;
try {
// 计数器,记录当前选择执行的轮数
int selectCnt = 0;
// 获取当前select()开始的时间点
long currentTimeNanos = System.nanoTime();
// delayNanos():从定时任务队列中取出一个定时任务,计算其还有多久就要执行了
// selectDeadLineNanos : 表示这个定时任务要开始执行的时间点
long selectDeadLineNanos = currentTimeNanos + delayNanos(currentTimeNanos);
for (;;) {
// --------------------- 1 处理定时任务 ------------------
// 对于马上就要到执行时间的定时任务,立即进行选择
long timeoutMillis = (selectDeadLineNanos - currentTimeNanos + 500000L) / 1000000L;
if (timeoutMillis <= 0) {
if (selectCnt == 0) {
// 非阻塞选择
selector.selectNow();
selectCnt = 1;
}
break;
}
// --------------------- 2 在选择期间,任务队列中有新任务加入 ------------------
// If a task was submitted when wakenUp value was true, the task didn't get a chance to call
// Selector#wakeup. So we need to check task queue again before executing select operation.
// If we don't, the task might be pended until select operation was timed out.
// It might be pended until idle timeout if IdleStateHandler existed in pipeline.
if (hasTasks() && wakenUp.compareAndSet(false, true)) {
// 非阻塞选择 只要有通道就绪就立刻返回
selector.selectNow();
selectCnt = 1;
break;
}
// --------------------- 3 阻塞式选择 ------------------
// select()方法结束的条件:
// 1)有channel被选择
// 2)seleter.wakeup()被调用
// 3)当前线程被打断
// 4)阻塞时间超时
// 5)其实这里还有一个结束的条件:
// 当长时间没有就绪的channel时,轮询会出现长时间空转,从而会导致CPU占用率飙升,
// 此时会使select()结束
// 注意,timeoutMillis 在这里是作为select()的阻塞时长的
int selectedKeys = selector.select(timeoutMillis);
selectCnt ++;
if (selectedKeys != 0 || oldWakenUp || wakenUp.get() || hasTasks() || hasScheduledTasks()) {
// - Selected something, 有channel被选择
// - waken up by user, or 或 seleter.wakeup()被调用
// - the task queue has a pending task. // 任务队列中有挂起的任务
// - a scheduled task is ready for processing // 有定时任务
break;
}
// --------------------- 4 处理Nio中的Bug ------------------
if (Thread.interrupted()) {
// Thread was interrupted so reset selected keys and break so we not run into a busy loop.
// As this is most likely a bug in the handler of the user or it's client library we will
// also log it.
//
// See https://github.com/netty/netty/issues/2426
if (logger.isDebugEnabled()) {
logger.debug("Selector.select() returned prematurely because " +
"Thread.currentThread().interrupt() was called. Use " +
"NioEventLoop.shutdownGracefully() to shutdown the NioEventLoop.");
}
selectCnt = 1;
break;
}
// 代码走到这里,说明select()结束的条件是4)或5)
// 记录当前时间
long time = System.nanoTime();
// 下面的式子等价于:
// time - currentTimeNanos >= TimeUnit.MILLISECONDS.toNanos(timeoutMillis)
// 当前for循环已经执行的时长 >= 阻塞时长
// 若if的这个条件成立,说明前面的select()方法是通过条件4)结束的
if (time - TimeUnit.MILLISECONDS.toNanos(timeoutMillis) >= currentTimeNanos) {
// timeoutMillis elapsed without anything selected.
selectCnt = 1;
// 执行else说明 当前for循环已经执行的时长 < 阻塞时长 ,说明前面的select()是通过
// 条件5)结束的。若空转次数大于等于指定的阈值512,则重新构建selector
} else if (SELECTOR_AUTO_REBUILD_THRESHOLD > 0 &&
selectCnt >= SELECTOR_AUTO_REBUILD_THRESHOLD) {
// The code exists in an extra method to ensure the method is not too big to inline as this
// branch is not very likely to get hit very frequently.
selector = selectRebuildSelector(selectCnt);
selectCnt = 1;
break;
}
currentTimeNanos = time;
}
if (selectCnt > MIN_PREMATURE_SELECTOR_RETURNS) {
if (logger.isDebugEnabled()) {
logger.debug("Selector.select() returned prematurely {} times in a row for Selector {}.",
selectCnt - 1, selector);
}
}
} catch (CancelledKeyException e) {
if (logger.isDebugEnabled()) {
logger.debug(CancelledKeyException.class.getSimpleName() + " raised by a Selector {} - JDK bug?",
selector, e);
}
// Harmless exception - log anyway
}
}
processSelectedKeys 跟进来
private void processSelectedKeys() {
// 若selectedKeys是优化过的
if (selectedKeys != null) {
// 优化的
processSelectedKeysOptimized();
} else {
// 一般的
processSelectedKeysPlain(selector.selectedKeys());
}
}
private void processSelectedKeysOptimized() {
for (int i = 0; i < selectedKeys.size; ++i) {
final SelectionKey k = selectedKeys.keys[i];
// null out entry in the array to allow to have it GC'ed once the Channel close
// See https://github.com/netty/netty/issues/2363
// 其就相当于对set集合处理时,要将处理过的key从set集合中删除是一样的,
// 为了避免对key的重复处理
selectedKeys.keys[i] = null;
// 对于NioEventLoop,key中的附件attachement中存放的是当前key所关联的NioChannel
final Object a = k.attachment();
if (a instanceof AbstractNioChannel) {
// 处理当前遍历的key
processSelectedKey(k, (AbstractNioChannel) a);
} else {
@SuppressWarnings("unchecked")
NioTask<SelectableChannel> task = (NioTask<SelectableChannel>) a;
processSelectedKey(k, task);
}
if (needsToSelectAgain) {
// null out entries in the array to allow to have it GC'ed once the Channel close
// See https://github.com/netty/netty/issues/2363
selectedKeys.reset(i + 1);
selectAgain();
i = -1;
}
}
}
private void processSelectedKey(SelectionKey k, AbstractNioChannel ch) {
final AbstractNioChannel.NioUnsafe unsafe = ch.unsafe();
// 处理key失效的情况
if (!k.isValid()) {
final EventLoop eventLoop;
try {
eventLoop = ch.eventLoop();
} catch (Throwable ignored) {
// If the channel implementation throws an exception because there is no event loop, we ignore this
// because we are only trying to determine if ch is registered to this event loop and thus has authority
// to close ch.
return;
}
// Only close ch if ch is still registered to this EventLoop. ch could have deregistered from the event loop
// and thus the SelectionKey could be cancelled as part of the deregistration process, but the channel is
// still healthy and should not be closed.
// See https://github.com/netty/netty/issues/5125
if (eventLoop != this || eventLoop == null) {
return;
}
// close the channel if the key is not valid anymore
unsafe.close(unsafe.voidPromise());
return;
}
try {
// 获取到当前key所有就绪的操作
int readyOps = k.readyOps();
// We first need to call finishConnect() before try to trigger a read(...) or write(...) as otherwise
// the NIO JDK channel implementation may throw a NotYetConnectedException.
// 若就绪操作中包含连接操作,处理连接就绪
if ((readyOps & SelectionKey.OP_CONNECT) != 0) {
// remove OP_CONNECT as otherwise Selector.select(..) will always return without blocking
// See https://github.com/netty/netty/issues/924
int ops = k.interestOps();
ops &= ~SelectionKey.OP_CONNECT;
k.interestOps(ops);
// 进行连接
unsafe.finishConnect();
}
// Process OP_WRITE first as we may be able to write some queued buffers and so free memory.
// 处理写就绪
// 当将数据写入到buffer,那么当前channel就处于写就绪
if ((readyOps & SelectionKey.OP_WRITE) != 0) {
// Call forceFlush which will also take care of clear the OP_WRITE once there is nothing left to write
ch.unsafe().forceFlush();
}
// Also check for readOps of 0 to workaround possible JDK bug which may otherwise lead
// to a spin loop
// 处理读就绪 或 接收连接就绪
if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
unsafe.read();
}
} catch (CancelledKeyException ignored) {
unsafe.close(unsafe.voidPromise());
}
}
runAllTasks 跟进来
【SingleThreadEventExecutor】#runAllTasks
protected boolean runAllTasks(long timeoutNanos) {
// // 将所有定时任务队列中的任务添加到taskQueue
fetchFromScheduledTaskQueue();
// 从taskQueue中获取一个任务
Runnable task = pollTask();
// 若该任务为null,说明当前任务队列中没有任务了,
// 此时执行tailTasks中的收尾任务
if (task == null) {
afterRunningAllTasks();
return false;
}
// 计算taskQueue中所有任务执行完毕的时间
final long deadline = ScheduledFutureTask.nanoTime() + timeoutNanos;
long runTasks = 0;
long lastExecutionTime;
// 遍历执行taskQueue中的所有任务
for (;;) {
// 执行当前遍历的任务
safeExecute(task);
runTasks ++;
// Check timeout every 64 tasks because nanoTime() is relatively expensive.
// XXX: Hard-coded value - will make it configurable if it is really a problem.
// 每64次任务检查一次超时
if ((runTasks & 0x3F) == 0) {
lastExecutionTime = ScheduledFutureTask.nanoTime();
if (lastExecutionTime >= deadline) {
break;
}
}
task = pollTask();
if (task == null) {
lastExecutionTime = ScheduledFutureTask.nanoTime();
break;
}
} // end-for
// 执行tailTasks中的收尾任务
afterRunningAllTasks();
this.lastExecutionTime = lastExecutionTime;
return true;
}
fetchFromScheduledTaskQueue跟进去
// 将所有定时任务队列中的任务添加到taskQueue
private boolean fetchFromScheduledTaskQueue() {
// 获取当前时间相对于定时任务实例创建时间的时长(定时任务实例已经存活了多久)
long nanoTime = AbstractScheduledEventExecutor.nanoTime();
// 从定时任务队列中取出一个最紧急的任务
Runnable scheduledTask = pollScheduledTask(nanoTime);
while (scheduledTask != null) {
// 在定时任务不空的前提下,将任务添加到taskQueue
if (!taskQueue.offer(scheduledTask)) {
// No space left in the task queue add it back to the scheduledTaskQueue so we pick it up again.
// 若没有添加成功,则重新放回到定时任务队列
scheduledTaskQueue().add((ScheduledFutureTask<?>) scheduledTask);
return false;
}
// 从定时任务队列中再取出一个最紧急的任务
scheduledTask = pollScheduledTask(nanoTime);
}
return true;
}
【AbstractScheduledEventExecutor】#pollScheduledTask
protected final Runnable pollScheduledTask(long nanoTime) {
assert inEventLoop();
// 从定时任务队列中取一个任务
Queue<ScheduledFutureTask<?>> scheduledTaskQueue = this.scheduledTaskQueue;
ScheduledFutureTask<?> scheduledTask = scheduledTaskQueue == null ?
null : scheduledTaskQueue.peek();
if (scheduledTask == null) {
return null;
}
// 若配置的需要推迟的时间比当前的时间还要小,说明这个任务早就应该执行了
if (scheduledTask.deadlineNanos() <= nanoTime) {
// 从定时任务队列中删除该任务
scheduledTaskQueue.remove();
// 返回该任务,以将其添加到taskQUeue去执行
return scheduledTask;
}
return null;
}
pollTask();跟进去
protected static Runnable pollTaskFrom(Queue<Runnable> taskQueue) {
// 从任务队列中取出一个任务,只要其不是一个唤醒任务,则直接返回
for (;;) {
Runnable task = taskQueue.poll();
if (task == WAKEUP_TASK) {
continue;
}
return task;
}
}
afterRunningAllTasks();跟进来
【SingleThreadEventExecutor】#runAllTasks
protected final boolean runAllTasksFrom(Queue<Runnable> taskQueue) {
// 从任务队列中获取一个任务
Runnable task = pollTaskFrom(taskQueue);
if (task == null) {
return false;
}
for (;;) {
safeExecute(task);
task = pollTaskFrom(taskQueue);
// task为null,说明taskQueue中的任务全部执行完毕
if (task == null) {
return true;
}
}
}
protected static void safeExecute(Runnable task) {
try {
// 任务的run()最终在这里执行了
task.run();
} catch (Throwable t) {
logger.warn("A task raised an exception. Task: {}", task, t);
}
}
chooserFactory.newChooser跟进来
@Override
public EventExecutorChooser newChooser(EventExecutor[] executors) {
// 判断length是否是2的整数次幂
if (isPowerOfTwo(executors.length)) {
// 2次幂EventExecutor选择器
return new PowerOfTwoEventExecutorChooser(executors);
} else {
// 普通EventExecutor选择器
return new GenericEventExecutorChooser(executors);
}
}
AbstractBootstrap#doBind0
– AbstractChannel#bind
--AbstractChannelHandlerContext#bind
** invokeBind()
--DefaultChannelPipeline – HeadContext#bind
– AbstractChannel#bind
--NioSocketChannel#doBind
NettyClient端源码
public static void main(String[] args) throws InterruptedException {
NioEventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(NioSocketChannel.class)
.localAddress("127.0.0.1", 8000)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new SomeClientHandler());
}
});
ChannelFuture future = bootstrap.connect("localhost", 8888).sync();
future.channel().closeFuture().sync();
} finally {
group.shutdownGracefully();
}
}
connect跟进去
【Bootstrap】#connect
public ChannelFuture connect(String inetHost, int inetPort) {
return connect(InetSocketAddress.createUnresolved(inetHost, inetPort));
}
private ChannelFuture doResolveAndConnect(final SocketAddress remoteAddress, final SocketAddress localAddress) {
// 创建并初始化了channel,然后将channel注册到了selector
final ChannelFuture regFuture = initAndRegister();
final Channel channel = regFuture.channel();
// 若异步操作完成:成功,或异常
if (regFuture.isDone()) {
if (!regFuture.isSuccess()) {
return regFuture;
}
// 解析地址,并连接Server
return doResolveAndConnect0(channel, remoteAddress, localAddress, channel.newPromise());
} 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 {
// Directly obtain the cause and do a null check so we only need one volatile read in case of a
// failure.
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();
doResolveAndConnect0(channel, remoteAddress, localAddress, promise);
}
}
});
return promise;
}
}
doResolveAndConnect0跟进去
private ChannelFuture doResolveAndConnect0(final Channel channel, SocketAddress remoteAddress,
final SocketAddress localAddress, final ChannelPromise promise) {
try {
// 获取到当前channel所绑定的eventLoop
final EventLoop eventLoop = channel.eventLoop();
// 创建一个地址解析器(其中封装着一个格式匹配器)
final AddressResolver<SocketAddress> resolver = this.resolver.getResolver(eventLoop);
// 若地址解析器不支持指定的Server的地址,或该地址已经被解析过了
if (!resolver.isSupported(remoteAddress) || resolver.isResolved(remoteAddress)) {
// Resolver has no idea about what to do with the specified remote address or it's resolved already.
doConnect(remoteAddress, localAddress, promise);
return promise;
}
// 解析Server地址:将主机名映射为ip
final Future<SocketAddress> resolveFuture = resolver.resolve(remoteAddress);
//下边有异步监听,有什么区别
//区别在于 resolveFuture 执行完马上执行当前的。 resolver.resolve 解析异步的过程不关心
// 若异步操作直接结束:成功,或异常
if (resolveFuture.isDone()) {
final Throwable resolveFailureCause = resolveFuture.cause();
// 若异常,则关闭channel,修改异步结果
if (resolveFailureCause != null) {
// Failed to resolve immediately
channel.close();
promise.setFailure(resolveFailureCause);
} else {
// Succeeded to resolve immediately; cached? (or did a blocking lookup)
// 若成功,则连接Server
// resolveFuture.getNow() 直接获取异步结果
doConnect(resolveFuture.getNow(), localAddress, promise);
}
return promise;
}
// Wait until the name resolution is finished.
// 为异步操作添加监听器:异步操作结束:成功,或异常
resolveFuture.addListener(new FutureListener<SocketAddress>() {
@Override
public void operationComplete(Future<SocketAddress> future) throws Exception {
if (future.cause() != null) {
channel.close();
promise.setFailure(future.cause());
} else {
doConnect(future.getNow(), localAddress, promise);
}
}
});
} catch (Throwable cause) {
promise.tryFailure(cause);
}
return promise;
}
doConnect跟进去
private static void doConnect(
final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise connectPromise) {
// This method is invoked before channelRegistered() is triggered. Give user handlers a chance to set up
// the pipeline in its channelRegistered() implementation.
final Channel channel = connectPromise.channel();
channel.eventLoop().execute(new Runnable() {
@Override
public void run() {
if (localAddress == null) {
channel.connect(remoteAddress, connectPromise);
} else {
channel.connect(remoteAddress, localAddress, connectPromise);
}
connectPromise.addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
}
});
}
channel.connect(remoteAddress, localAddress, connectPromise);跟进去
【AbstractChannel】#connect
@Override
public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
return pipeline.connect(remoteAddress, localAddress, promise);
}
【AbstractChannelHandlerContext】#connect
public ChannelFuture connect(
final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise promise) {
if (remoteAddress == null) {
throw new NullPointerException("remoteAddress");
}
if (isNotValidPromise(promise, false)) {
// cancelled
return promise;
}
final AbstractChannelHandlerContext next = findContextOutbound(MASK_CONNECT);
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
next.invokeConnect(remoteAddress, localAddress, promise);
} else {
safeExecute(executor, new Runnable() {
@Override
public void run() {
next.invokeConnect(remoteAddress, localAddress, promise);
}
}, promise, null);
}
return promise;
}
【AbstractChannelHandlerContext】#invokeConnect
private void invokeConnect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
if (invokeHandler()) {
try {
((ChannelOutboundHandler) handler()).connect(this, remoteAddress, localAddress, promise);
} catch (Throwable t) {
notifyOutboundHandlerException(t, promise);
}
} else {
connect(remoteAddress, localAddress, promise);
}
}
【AbstractNioChannel】#connect
@Override
public final void connect(
final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise promise) {
if (!promise.setUncancellable() || !ensureOpen(promise)) {
return;
}
try {
if (connectPromise != null) {
// Already a connect in process.
throw new ConnectionPendingException();
}
boolean wasActive = isActive();
if (doConnect(remoteAddress, localAddress)) {
fulfillConnectPromise(promise, wasActive);
} else {
connectPromise = promise;
requestedRemoteAddress = remoteAddress;
// Schedule connect timeout.
int connectTimeoutMillis = config().getConnectTimeoutMillis();
if (connectTimeoutMillis > 0) {
connectTimeoutFuture = eventLoop().schedule(new Runnable() {
@Override
public void run() {
ChannelPromise connectPromise = AbstractNioChannel.this.connectPromise;
ConnectTimeoutException cause =
new ConnectTimeoutException("connection timed out: " + remoteAddress);
if (connectPromise != null && connectPromise.tryFailure(cause)) {
close(voidPromise());
}
}
}, connectTimeoutMillis, TimeUnit.MILLISECONDS);
}
promise.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isCancelled()) {
if (connectTimeoutFuture != null) {
connectTimeoutFuture.cancel(false);
}
connectPromise = null;
close(voidPromise());
}
}
});
}
} catch (Throwable t) {
promise.tryFailure(annotateConnectException(t, remoteAddress));
closeIfClosed();
}
}
doConnect跟进去
【NioSocketChannel】#doConnect
@Override
protected boolean doConnect(SocketAddress remoteAddress, SocketAddress localAddress) throws Exception {
if (localAddress != null) {
// 将本地地址绑定到channel
doBind0(localAddress);
}
boolean success = false;
try {
// 客户端的连接就绪指的是,若Client直接连接成功,
// 就成功了。若失败,则Client的连接操作就绪
// 连接Server
boolean connected = SocketUtils.connect(javaChannel(), remoteAddress);
if (!connected) {
// 初始化当前channel的key感兴趣的操作
selectionKey().interestOps(SelectionKey.OP_CONNECT);
}
success = true;
return connected;
} finally {
if (!success) {
doClose();
}
}
}
pipeline分析
处理器封装成一个节点添加到pipeline中
pipeline什么时候创建的,
指定常见channel类型 比如 NioServerSocketChannel时创建的
pipeline存的是 处理器添加成节点存进去的。本质上是个双向链表。有个头节点head、tail尾节点。处理器封装成了节点Context,放入pipeline,添加处理器有个封装的过程。
protected AbstractChannel(Channel parent) {
this.parent = parent;
// 为Netty的channel生成id
id = newId();
// 底层操作对象
unsafe = newUnsafe();
// 创建当前channel所绑定的channelPipeline
pipeline = newChannelPipeline();
}
protected DefaultChannelPipeline(Channel channel) {
this.channel = ObjectUtil.checkNotNull(channel, "channel");
succeededFuture = new SucceededChannelFuture(channel, null);
voidPromise = new VoidChannelPromise(channel, true);
tail = new TailContext(this);
head = new HeadContext(this);
head.next = tail;
tail.prev = head;
}
tailContext跟进去
TailContext(DefaultChannelPipeline pipeline) {
// 参数1:当前节点所要加入的pipeline
// 参数2:当前节点封装的执行器executor
// 参数3:节点名称
// 参数4:节点类型
super(pipeline, null, TAIL_NAME, TailContext.class);
// 修改当前节点所封装处理器的状态
setAddComplete();
}
super跟进去
AbstractChannelHandlerContext(DefaultChannelPipeline pipeline, EventExecutor executor,
String name, Class<? extends ChannelHandler> handlerClass) {
this.name = ObjectUtil.checkNotNull(name, "name");
this.pipeline = pipeline;
this.executor = executor;
// 初始化执行标识
this.executionMask = mask(handlerClass);
// Its ordered if its driven by the EventLoop or the given Executor is an instanceof OrderedEventExecutor.
ordered = executor == null || executor instanceof OrderedEventExecutor;
}
mark方法用于判断初始化标识的
mark–>mark0—>isSkippable方法
private static boolean isSkippable(
final Class<?> handlerType, final String methodName, final Class<?>... paramTypes) throws Exception {
return AccessController.doPrivileged(new PrivilegedExceptionAction<Boolean>() {
@Override
public Boolean run() throws Exception {
// 若当前方法上出现了@Skip注解,则返回true
return handlerType.getMethod(methodName, paramTypes).isAnnotationPresent(Skip.class);
}
});
}
一般都会重写InboundHandler 或者OutboundHandler中的方法,不如channelRead,ChannelInboundHandlerAdapter方法中都会默认加上@Skip注解,我们重写的channelRead方法没有@Skip注解,就不会过滤掉,就会去执行。
ChannelInitializer创建时机
ChannelInitializer类上有个@Sharable注解,这个注解的意思是共享的,加上注解ChannelInitializer类就是共享的。
分析ChannelInitializer中的initchannel是什么时候执行的
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
// 获取channel中的Pipeline
ChannelPipeline pipeline = ch.pipeline();
// StringDecoder:字符串解码器,将Channel中的ByteBuf数据解码为String
pipeline.addLast(new StringDecoder());
// StringEncoder:字符串编码器,将String编码为将要发送到Channel中的ByteBuf
pipeline.addLast(new StringEncoder());
pipeline.addLast(new SomeServerHandler());
}
});
当client连接上的server端的时候,就会调用channelRead方法,这个方法里面有child.pipeline().addLast(childHandler);方法,先初始化这个子channel,将子channel注册到selector上,就会调用ChannelInitializer类中的handlerAdded方法,这个方法只要有客户端连接就会触发这个方法,接着就会调用自定义的ChannelInitializer实例的initChannel(),执行这个方法后就会进入当前上面的这个匿名内部类initchannel方法中。
handlerAdd方法的执行
ChannelInitializer类
每来一个client请求就会进入initchannel方法。
对于parentchannel监听的一个端口,ChannelInitializer是共享的 单列。 ChannelHandlerContext是多列的。是在addLast创建的,添加到pipeline。不同的pipeline里面添加的ctx实例是不一样的。
-
server端启动一个端口,会绑定一个channel,添加一个连接处理器。server端可以同时启动多个端口,
-
一个parentChannel对应多个childChannel。
-
一个parentChannel会对应一个连接处理器(ServerBootstrapAcceptor),一个连接处理器里面对应一个childHandler,会对应一个ChannelInitializer实例。所以ChannelInitializer是共享的,childHandler就是共享的
-
所以一个ChannelInitializer实例注册到多个pipeline。
-
对于parentchannel监听的一个端口,ChannelInitializer是共享的 单列。 ChannelHandlerContext是多列的。是在addLast创建的,添加到pipeline。不同的pipeline里面添加的ctx实例是不一样的。
-
parentchannel监听多个端口,就会产生多个ChannelInitializer,在一个监听的端口中,ChannelInitializer只会创建一次, 在一个channel实例里面仅有一个,在所有的childChannel里面ChannelInitializer是共享的。
-
ChannelInitializer被添加到各个子channel的pipeline中,被各个pipeline封装成节点ctx。也就是说ChannelInitializer实例会被多个pipline以封装成节点来使用。
ChannelInitializer的最终父级是channelHandler,ChannelInitializer是共享的,里面有个initMap,存的是ChannelHandlerContext,每个client请求过来后调用initChannel,把ChannelHandlerContext加入到initMap中,用完就删除了ChannelHandlerContext,意思就是每次client一个请求过来调用完就把initMap中的ChannelHandlerContext删除了,但是ChannelInitializer是共享的,ChannelInitializer不会删除,只会删除initmap中的ChannelHandlerContext。
处理器的添加
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 the registered is false it means that the channel was not registered on an eventLoop yet.
// In this case we add the context to the pipeline and add a task that will call
// ChannelHandler.handlerAdded(...) once the channel is registered.
if (!registered) {
newCtx.setAddPending();
callHandlerCallbackLater(newCtx, true);
return this;
}
EventExecutor executor = newCtx.executor();
if (!executor.inEventLoop()) {
callHandlerAddedInEventLoop(newCtx, executor);
return this;
}
}
// 触发handlerAdded()方法的执行
callHandlerAdded0(newCtx);
return this;
}
newContext方法 跟进去
private AbstractChannelHandlerContext newContext(EventExecutorGroup group, String name, ChannelHandler handler) {
return new DefaultChannelHandlerContext(this, childExecutor(group), name, handler);
}
private EventExecutor childExecutor(EventExecutorGroup group) {
if (group == null) {
return null;
}
// 该值用于决定是否为每个group固定一个executor
Boolean pinEventExecutor = channel.config()
.getOption(ChannelOption.SINGLE_EVENTEXECUTOR_PER_GROUP);
// 若pinEventExecutor的值为false,则不为group绑定executor,就会为每一个
// 节点从group中轮询一个executor
if (pinEventExecutor != null && !pinEventExecutor) {
return group.next();
}
// 若pinEventExecutor的值为true,则为每一个group固定一个不变的executor
// map的key为group,value为其指定的用于固定的executor
Map<EventExecutorGroup, EventExecutor> childExecutors = this.childExecutors;
if (childExecutors == null) {
// Use size of 4 as most people only use one extra EventExecutor.
childExecutors = this.childExecutors =
new IdentityHashMap<EventExecutorGroup, EventExecutor>(4);
}
// Pin one of the child executors once and remember it so that the same child executor
// is used to fire events for the same channel.
EventExecutor childExecutor = childExecutors.get(group);
if (childExecutor == null) {
childExecutor = group.next();
childExecutors.put(group, childExecutor);
}
return childExecutor;
}
Channel 的 inBound 与 outBound 处理器
inBound 从head节点开始
outBound从tail节点开始
总结
客户端连接请求的处理只需要一个channel,这个channel绑定的EventLoop只需要一个,从parentGroup拿,
举例:server端启动7777端口:client连接7777端口,server端有一个连接处理器,一个channel就有一个这样的实例,client传来的msg,channelRead就接收到了,为每个client创建一个chlidChannel, chlidChannel也需要注册,注册到selector, chaildChannel要绑定EventLoop,这个EventLoop来自childGroup。
经过生产下实践证明的,一般对于百万级的QPS,parentGroup设置为2,childGroup设置为4,就完全没问题