1. 概述
Netty是一個穩定、高性能NIO通信框架,它對JDK NIO的使用做了很好的封裝,對使用者屏蔽了NIO通信的底層細節,對使用NIO降低業務開發工作量,降低開發難度
2. Netty IO Reactor模型

3. Netty服務端啓動流程
4. Netty組件分析
4.1 EventLoopGroup
Netty處理IO請求線程池,管理一組線程處理IO請求。啓動一個Netty服務,會初始化兩個線程組,主線程組和工作線程組。主線程組會啓動一個線程,接收客戶端請求,將接收到的連接註冊到工作線程組一個線程,交給工作組線程處理具體IO讀寫操作;工作線程組會啓動一組線程,處理具體IO讀寫工作。
線程組線程初始化工作是在構造函數中完成,通過指定線程組大小,初始化線程組管理線程數。
protected EventLoop newChild(Executor executor, Object... args) throws Exception {
return new NioEventLoop(this, executor, (SelectorProvider) args[0],
((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2]);
}
初始化的線程會委託給EventExecutorChooser管理,對於IO請求,它會按照一定的策略將IO請求轉交給一個具體線程來處理。
EventLoopGroup實際是管理一組EventLoop線程,具體IO處理是交給EventLoop類來處理的。
4.2 NioEventLoop
NioEventLoop是實際處理IO讀寫的線程,每個NioEventLoop會啓動一個線程,循環遍歷,處理IO讀寫任務。NioEventLoop有一個Selector,IO channel會被註冊到Selector上。NioEventLoop會維護一個taskQueue隊列,分配到的Runnable會放入taskQueue隊列中,在循環遍歷線程中,會取出Runnable進行處理。
對於每個EventLoop都有一個線程運行,這個線程通過startThread()啓動。這個線程的啓動有點繞,每個EventLoop持有一個ThreadPerTaskExecutor,ThreadPerTaskExecutor.execute()執行 DefaultThreadFactory.newThread(command).start()啓動線程。這個線程會啓動一個循環遍歷,監聽IO讀寫和順序執行隊列任務。
4.3 NioServerSocketChannel
Channel組件是IO讀寫通道,NioServerSocketChannel接收客戶端連接請求,NioSocketChannel處理連接讀寫請求。Channel處理IO讀寫任務委託給Unsafe和ChannelPipeline組件,Unsafe處理Channel讀寫任務,ChannelPipeline是讀寫請求處理鏈,可以在處理鏈中添加處理邏輯。
protected AbstractChannel(Channel parent) {
this.parent = parent;
id = newId();
unsafe = newUnsafe();
pipeline = newChannelPipeline();
}
Unsafe是Channel的內部類,可以方便使用Channel持有的資源。對於NioServerSocketChannel,NioMessageUnsafe.read()接收客戶端連接請求,然後調用pipeline.fireChannelRead()觸發調用鏈執行,ServerBootstrapAcceptor處理客戶端連接請求,將客戶端請求連接註冊到工作線程組。對於NioSocketChannel,NioByteUnsafe.read()處理IO讀寫。
4.4 ServerBootstrap
組合使用Nettty各個組件,啓動Netty服務。它定義了一個Netty使用的門面,屏蔽了內部複雜的邏輯,方便的啓動一個Netty服務。
public final class EchoServer {
static final int PORT = Integer.parseInt(System.getProperty("port", "8007"));
public static void main(String[] args) throws Exception {
// Configure the server.
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
final EchoServerHandler serverHandler = new EchoServerHandler();
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();
//p.addLast(new LoggingHandler(LogLevel.INFO));
p.addLast(serverHandler);
}
});
// 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();
}
}
}
ServerBootstrap定義兩個EventLoopGroup線程組,一個處理客戶端連接請求,一個處理接收連接IO讀寫請求。調用bind()方法,完成服務端的啓動。bind()依次會調用initAndRegister()和doBind0()。
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
channel = channelFactory.newChannel(); 【1】
init(channel); 【2】
} catch (Throwable t) {
}
ChannelFuture regFuture = config().group().register(channel); 【3】
if (regFuture.cause() != null) {
if (channel.isRegistered()) {
channel.close();
} else {
channel.unsafe().closeForcibly();
}
}
return regFuture;
}
- 使用反射生成.channel(NioServerSocketChannel.class)方法指定的NioServerSocketChannel對象
-
設置channel參數,在channel pipeline中添加ServerBootstrapAcceptor處理邏輯,用於接收客戶端請求處理
void init(Channel channel) throws Exception { final Map<ChannelOption<?>, Object> options = options0(); synchronized (options) { setChannelOptions(channel, options, logger); } final Map<AttributeKey<?>, Object> attrs = attrs0(); synchronized (attrs) { for (Entry<AttributeKey<?>, Object> e: attrs.entrySet()) { @SuppressWarnings("unchecked") AttributeKey<Object> key = (AttributeKey<Object>) e.getKey(); channel.attr(key).set(e.getValue()); } } ChannelPipeline p = channel.pipeline(); 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)); } p.addLast(new ChannelInitializer<Channel>() { @Override public void initChannel(final Channel ch) throws Exception { final ChannelPipeline pipeline = ch.pipeline(); ChannelHandler handler = config.handler(); if (handler != null) { pipeline.addLast(handler); } ch.eventLoop().execute(new Runnable() { @Override public void run() { pipeline.addLast(new ServerBootstrapAcceptor( ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs)); } }); } }); }
-
將channel添加到EventLoopGroup線程組的NioEventLoop線程上,NioEventLoop線程啓動循環遍歷,處理channel連接請求。當接收到客戶端連接請求,會執行ServerBootstrapAcceptor邏輯,將接收到的請求添加到worker線程組一個NioEventLoop線程上,NioEventLoop線程啓動循環遍歷處理客戶端IO讀寫請求。每個NioEventLoop線程都有一個Selector,channel註冊到Selector上。
4.5 ServerBootstrapAcceptor
作爲NioServerSocketChannel處理鏈中的一個Handler,處理客戶端連接請求。NioServerSocketChannel收到客戶端連接請求,pipeline.fireChannelRead()調用處理鏈。
接收到的客戶端請求channel會添加到工作線程組,處理IO讀寫請求。
public void channelRead(ChannelHandlerContext ctx, Object msg) {
// 客戶端連接channel
final Channel child = (Channel) msg;
// channel pipeline
child.pipeline().addLast(childHandler);
// 設置channel參數
setChannelOptions(child, childOptions, logger);
for (Entry<AttributeKey<?>, Object> e: childAttrs) {
child.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());
}
try {
// 將channel添加到工作線程組
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);
}
}