服务端启动代码如下
public class EchoServer {
static final int PORT = 8001;
public static void main(String[] args) {
// 1. 声明线程池
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
// 2. 服务端引导器
ServerBootstrap serverBootstrap = new ServerBootstrap();
// 3. 设置线程池
serverBootstrap.group(bossGroup, workerGroup)
// 4. 设置ServerSocketChannel的类型
.channel(NioServerSocketChannel.class)
// 5. 设置参数
.option(ChannelOption.SO_BACKLOG, 100)
// 6. 设置ServerSocketChannel对应的Handler,只能设置一个
.handler(new LoggingHandler(LogLevel.INFO))
// 7. 设置SocketChannel对应的Handler
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
// 可以添加多个子Handler
p.addLast(new LoggingHandler(LogLevel.INFO));
p.addLast(new EchoServerHandler());
}
});
// 8. 绑定端口
ChannelFuture f = serverBootstrap.bind(PORT).sync();
// 9. 等待服务端监听端口关闭,这里会阻塞主线程
f.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 10. 优雅地关闭两个线程池
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
服务端启动的入口是下面这行代码
ChannelFuture f = serverBootstrap.bind(PORT).sync();
这里主要有两个方法,一个是bind()
,一个是sync()
,服务端的启动逻辑在bind()
方法里,在这里打个断点启动程序。
doBind
public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
public ChannelFuture bind(int inetPort) {
return bind(new InetSocketAddress(inetPort));
}
public ChannelFuture bind(SocketAddress localAddress) {
// 做一些校验
validate();
return doBind(ObjectUtil.checkNotNull(localAddress, "localAddress"));
}
}
这里只传了一个端口进来,使用InetSocketAddress
类构造了一个地址,默认会生成一个0.0.0.0:8001
的地址。
接着往下走,进入到doBind
方法,开源框架中一般do
开头的都是做正事的。
public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
private ChannelFuture doBind(final SocketAddress localAddress) {
// key1 初始化并注册一些东西
final ChannelFuture regFuture = initAndRegister();
final Channel channel = regFuture.channel();
if (regFuture.cause() != null) {
// 注册失败
return regFuture;
}
// initAndRegister 里面使用异步的方式
if (regFuture.isDone()) {
// 走到这里, 说明上面已经注册完成
ChannelPromise promise = channel.newPromise();
// key2 绑定了什么呢?
// 是否会执行到这里 取决于initAndRegister()中异步执行的快慢,所以不一定到这里, 这里可以打一个断点
doBind0(regFuture, channel, localAddress, promise);
return promise;
} else {
// 走到这里, 说明还没有注册完成
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) {
// 注册失败
promise.setFailure(cause);
} else {
// 注册成功
promise.registered();
// key2 绑定了什么呢?
// 是否会执行到这里 取决于initAndRegister()中异步执行的快慢,所以不一定到这里, 这里可以打一个断点
doBind0(regFuture, channel, localAddress, promise);
}
}
});
return promise;
}
}
}
doBind
方法主要做了两件事:
initAndRegister()
初始化并注册一些东西doBind0
绑定一些东西,这里面其实就是调用Java NIO中java.nio.channels.ServerSocketChannel
的bind
方法
initAndRegister
继续进入initAndRegister()
方法
public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
// key1, 通过ChannelFactory创建一个 Channel, 使用反射的形式创建一个Channel
// 反射的类就是我们第4步中设置的 NioServerSocketChannel.class
channel = channelFactory.newChannel();
// key2 初始化 Channel
init(channel);
} catch (Throwable t) {
// 异常处理, 忽略
}
// key3 注册 Channel
// 这里用的是NioEventLoopGroup, 所以是将 Channel 注册到 NioEventLoop 中的 java.nio.channels.Selector
ChannelFuture regFuture = config().group().register(channel);
// 处理失败, 关闭Channel
if (regFuture.cause() != null) {
if (channel.isRegistered()) {
channel.close();
} else {
channel.unsafe().closeForcibly();
}
}
return regFuture;
}
}
initAndRegister()
方法主要做了三件事:
-
channelFactory.newChannel()
, 通过反射生成Channel(这里生成的是NioServerSocketChannel
), 而且是无参构造方法。 -
init(channel)
, 初始化Channel
-
config().group().register(channel)
, 将Channel
注册到某个地方。这里用的是NioEventLoopGroup
, 所以是将Channel
注册到NioEventLoop
中的java.nio.channels.Selector
channelFactory.newChannel()
我们这里使用的是NioServerSocketChannel
,直接查看它的无参构造方法。
public class NioServerSocketChannel extends AbstractNioMessageChannel
implements io.netty.channel.socket.ServerSocketChannel {
private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();
// 1. 无参构造方法
public NioServerSocketChannel() {
this(newSocket(DEFAULT_SELECTOR_PROVIDER));
}
// 1.1 使用Java底层的SelectorProvider创建一个Java原生的 java.nio.channels.ServerSocketChannel
// windows平台下使用的是Windows下的SelectorProvider, 因为ServerSocketChannel是跟操作系统交互的, 所以是平台相关的, 每个平台下都不一样
private static ServerSocketChannel newSocket(SelectorProvider provider) {
try {
return provider.openServerSocketChannel();
} catch (IOException e) {
throw new ChannelException(
"Failed to open a server socket.", e);
}
}
// 1.2 有参构造方法,参数是Java原生的ServerSocketChannel
public NioServerSocketChannel(ServerSocketChannel channel) {
// 调用父类的构造方法, 注意parent参数为null
// key, 感兴趣的事件为Accept事件
super(null, channel, SelectionKey.OP_ACCEPT);
// 创建ChannelConfig
config = new NioServerSocketChannelConfig(this, javaChannel().socket());
}
}
public abstract class AbstractNioMessageChannel extends AbstractNioChannel {
// 1.2.1
protected AbstractNioMessageChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
// 调用父类构造方法
super(parent, ch, readInterestOp);
}
}
查看父类方法
public abstract class AbstractNioChannel extends AbstractChannel {
// 1.2.1.1
protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
// 调用父类的构造方法,parent为null
super(parent);
// ch为Java原生的Channel
this.ch = ch;
// 监听事件, 这里为Accept事件
this.readInterestOp = readInterestOp;
try {
// 将channel设置为非阻塞
ch.configureBlocking(false);
} catch (IOException e) {
// 忽略异常......
}
}
}
继续看父类方法
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
// 1.2.1.1.1
protected AbstractChannel(Channel parent) {
// 此时parent为null
this.parent = parent;
// 生成一个id
id = newId();
// 这里调用的是 io.netty.channel.nio.AbstractNioMessageChannel.newUnsafe
// 返回的是 new NioMessageUnsafe()
unsafe = newUnsafe();
// 这里返回的是 DefaultChannelPipeline
pipeline = newChannelPipeline();
}
protected ChannelId newId() {
return DefaultChannelId.newInstance();
}
protected DefaultChannelPipeline newChannelPipeline() {
return new DefaultChannelPipeline(this);
}
}
看看DefaultChannelPipeline
实例化做了什么
public class DefaultChannelPipeline implements ChannelPipeline {
// 1.2.1.1.1.1
protected DefaultChannelPipeline(Channel channel) {
this.channel = ObjectUtil.checkNotNull(channel, "channel");
succeededFuture = new SucceededChannelFuture(channel, null);
voidPromise = new VoidChannelPromise(channel, true);
// ChannelPipeline中默认有两个节点,head和tail,且是双向链表
tail = new TailContext(this);
head = new HeadContext(this);
head.next = tail;
tail.prev = head;
}
}
NioServerSocketChannel
创建完成,主要做了如下几件事情
-
NioServerSocketChannel
里面会有一个Java原生的java.nio.channels.ServerSocketChannel
-
记录监听事件为Accept事件
-
为
Channel
分配一个id -
为
Channel
创建一个unsafe,io.netty.channel.nio.AbstractNioMessageChannel.NioMessageUnsafe
-
为
Channel
分配一个pipeline(DefaultChannelPipeline
),默认情况,这是一个双向链表:HeadContext<=>TailContext
init(channel)
接着看init(channel)
方法
public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel> {
@Override
void init(Channel channel) {
setChannelOptions(channel, newOptionsArray(), logger);
setAttributes(channel, newAttributesArray());
// 从Channel中取出ChannelPipeline, 上面创建的
ChannelPipeline p = channel.pipeline();
// 子Channel的配置, 子Channel也就是SocketChannel
final EventLoopGroup currentChildGroup = childGroup;
final ChannelHandler currentChildHandler = childHandler;
final Entry<ChannelOption<?>, Object>[] currentChildOptions = newOptionsArray(childOptions);
final Entry<AttributeKey<?>, Object>[] currentChildAttrs = newAttributesArray(childAttrs);
// 这里往ChannelPipeline中新增了一个 ChannelInitializer
// 里面有个initChannel方法, 后面有地方会回调这个方法
//
p.addLast(new ChannelInitializer<Channel>() {
@Override
public void initChannel(final Channel ch) {
final ChannelPipeline pipeline = ch.pipeline();
// 这里是第6步设置的LoggingHandler
ChannelHandler handler = config.handler();
if (handler != null) {
pipeline.addLast(handler);
}
// 这里使用异步的方式提交一个任务
ch.eventLoop().execute(new Runnable() {
@Override
public void run() {
// 往ChannelPipeline中新增了一个ChannelHandler
// 把子Channel相关的参数传到这个Handler里面
pipeline.addLast(new ServerBootstrapAcceptor(
ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}
});
}
});
}
}
此时的ChannelPipeline
链条为: HeadContext<=>ChannelInitializer<=>TailContext
config().group().register(channel)
查看源码,可以发现,这里的group()
返回的就是我们的bossGroup(NioEventLoopGroup)
,所以这里就是调用NioEventLoopGroup
的register(channel)
方法。
// NioEventLoopGroup
public abstract class MultithreadEventLoopGroup extends MultithreadEventExecutorGroup implements EventLoopGroup {
@Override
public ChannelFuture register(Channel channel) {
return next().register(channel);
}
@Override
public EventLoop next() {
// 这里会选择一个EventLoop(NioEventLoop)出来
return (EventLoop) super.next();
}
}
然后来到了EventLoop
的register(channel)
方法:
// NioEventLoopGroup
public abstract class SingleThreadEventLoop extends SingleThreadEventExecutor implements EventLoop {
@Override
public ChannelFuture register(Channel channel) {
return register(new DefaultChannelPromise(channel, this));
}
@Override
public ChannelFuture register(final ChannelPromise promise) {
ObjectUtil.checkNotNull(promise, "promise");
// 这里unsafe()返回的是 NioMessageUnsafe
promise.channel().unsafe().register(this, promise);
return promise;
}
}
最后,又调回了Channel
的Unsafe
的register()
方法,这里第一个参数是this
,也就是NioEventLoop
,第二个参数是刚创建的ChannelPromise
。
// io.netty.channel.nio.AbstractNioMessageChannel.NioMessageUnsafe
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
protected abstract class AbstractUnsafe implements Unsafe {
@Override
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
ObjectUtil.checkNotNull(eventLoop, "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;
}
// key1, 将上面传进来的EventLoop跟Channel进行绑定
AbstractChannel.this.eventLoop = eventLoop;
// 判断当前线程是否跟EventLoop线程是同一个, 这里肯定不是同一个, 所以会执行后面的else语句
if (eventLoop.inEventLoop()) {
// key2,调用register0
register0(promise);
} else {
try {
// 提交一个异步任务
eventLoop.execute(new Runnable() {
@Override
public void run() {
// key2, 调用register0, 可以在这里打个断点
register0(promise);
}
});
} catch (Throwable t) {
// 省略......
}
}
}
}
}
上面提交了一个异步任务,这里的EventLoop
为NioEventLoop
eventLoop.execute(new Runnable() {
@Override
public void run() {
// key2, 调用register0, 可以在这里打个断点
register0(promise);
}
});
NioEventLoop
类似于Java线程池里面的工作线程,每个NioEventLoop
里面有自己的任务队列。这里执行execute
,会先把任务放到任务队列中,然后再判断NioEventLoop
中的线程是否启动,如果没有,则会新建一个线程并启动,最终会执行NioEventLoop#run
方法,这里面有一个死循环,会执行任务队列里面的任务以及监听Socket
事件。
可以在这里打个断点看看里面的细节。
接着,跟踪到register0()
方法中:
// io.netty.channel.nio.AbstractNioMessageChannel.NioMessageUnsafe
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
protected abstract class AbstractUnsafe implements Unsafe {
private void register0(ChannelPromise promise) {
try {
// 做一些检查, 跳过
if (!promise.setUncancellable() || !ensureOpen(promise)) {
return;
}
boolean firstRegistration = neverRegistered;
// key1, 调用doRegister()方法
// 这里其实是将EventLoop中的Selector与Java原生的Channel绑定在一起
doRegister();
neverRegistered = false;
registered = true;
// key2,调用invokeHandlerAddedIfNeeded()
// 触发添加Handler的回调
// 前面init(channel)方法, 往ChannelPipeline总添加了一个ChannelInitializer, ChannelInitializer的initChannel方法就是在这一步完成的
// 这一步之后, 前面init(channel)方法添加的ChannelInitializer执行会执行initChannel方法后就会把自己移除掉
// 最后ChannelPipeline里面应该是: HeadContext<=>LoggineHandler<=>TailContext
// 而ServerBootstrapAcceptor还没有加入到ChannelPipeline中,
// 因为它设置了使用EventLoop的线程执行,当前线程就是EventLoop的线程
// 所以, 添加ServerBootstrapAcceptor会在当前任务执行完毕才会执行
pipeline.invokeHandlerAddedIfNeeded();
safeSetSuccess(promise);
// 调用ChannelPineline的fireChannelRegistered(), 实际是调用的各个ChannelHandler的channelRegistered()方法
//
pipeline.fireChannelRegistered();
// Channel是否已经激活, 此时还未绑定到具体的地址,所以还未激活
if (isActive()) {
if (firstRegistration) {
pipeline.fireChannelActive();
} else if (config().isAutoRead()) {
beginRead();
}
}
} catch (Throwable t) {
// 省略......
}
}
}
}
register0
方法执行完成后,ChannelPipeline
里面应该是:HeadContext<=>LoggineHandler<=>TailContext
接着看doRegister()
里面做了什么
public abstract class AbstractNioChannel extends AbstractChannel {
@Override
protected void doRegister() throws Exception {
boolean selected = false;
for (;;) {
try {
// key,将EventLoop中的Selector与Java原生的Channel绑定在一起
// 第三个参数是this, 这里就是NioServerSocketChannel
selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
return;
} catch (CancelledKeyException e) {
// 忽略......
}
}
}
}
这里的监听集合设置为了0, 也就是什么都不监听。后续应该有某个地方会需要修改这个selectionKey
的监听集合。
发现是在AbstractNioChannel#doBeginRead
这个方法里面,重新设置了监听SelectionKey.OP_ACCEPT
事件。
通过Debug发现,等NioServerSocketChannel
准备就绪后,会调用DefaultChannelPipeline#fireChannelActive
,进而触发到AbstractNioChannel#doBeginRead
方法。
到这里,initAndRegister()
方法内部就分析完成了。
还有个地方需要注意,前面往ChannelPipeline
中新增了一个ChannelInitializer
, 里面有个initChannel
方法,执行了如下操作
p.addLast(new ChannelInitializer<Channel>() {
@Override
public void initChannel(final Channel ch) {
final ChannelPipeline pipeline = ch.pipeline();
// 这里是第6步设置的LoggingHandler
ChannelHandler handler = config.handler();
if (handler != null) {
pipeline.addLast(handler);
}
// 这里使用异步的方式提交一个任务
ch.eventLoop().execute(new Runnable() {
@Override
public void run() {
// 往ChannelPipeline中新增了一个ChannelHandler
// 把子Channel相关的参数传到这个Handler里面
pipeline.addLast(new ServerBootstrapAcceptor(
ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}
});
}
});
因为这里使用的是异步的方式提交了一个任务,所以需要等前面的任务执行完成后才会执行到上面这个任务。
所以此时ChannelPipeline
里面还是:HeadContext<=>LoggineHandler<=>TailContext
。
doBind0
public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
private static void doBind0(
final ChannelFuture regFuture, final Channel channel,
final SocketAddress localAddress, final ChannelPromise promise) {
// 这里也是提交一个异步任务
channel.eventLoop().execute(new Runnable() {
@Override
public void run() {
if (regFuture.isSuccess()) {
// key, 调用Channel(NioServerSocketChannel)的bind()方法, 因为提交的是异步任务, 所以这里要打一个断点
channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
} else {
promise.setFailure(regFuture.cause());
}
}
});
}
}
上面往NioEventLoop
里面提交了一个一步任务。
NioEventLoop
会从任务队列里面获取任务并执行,会先执行到这个任务,该任务是在前面ChannelInitializer
里面的initChannel
方法提交的。
ch.eventLoop().execute(new Runnable() {
@Override
public void run() {
// 往ChannelPipeline中新增了一个ChannelHandler
// 把子Channel相关的参数传到这个Handler里面
pipeline.addLast(new ServerBootstrapAcceptor(
ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}
});
这个任务执行完后,此时ChannelPipeline里面应该是: HeadContext<=>LoggineHandler<=>ServerBootstrapAcceptor<=>TailContext
。
上面任务执行完,然后才会执行到doBind0
提交的任务。
// NioServerSocketChannel
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
@Override
public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
// 调用的是pipeline(DefaultChannelPipeline)的bind()方法
return pipeline.bind(localAddress, promise);
}
}
进入pipeline(DefaultChannelPipeline
)的bind()
方法
public class DefaultChannelPipeline implements ChannelPipeline {
@Override
public final ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
// 从尾开始调用,也就是outbound
return tail.bind(localAddress, promise);
}
}
此时的ChannelPipeline
:HeadContext<=>LoggineHandler<=>ServerBootstrapAcceptor<=>TailContext
outbound类型的pineple实际为HeadContext=>LoggingHandler=>TailContext
。
这里主要贴出重要代码
先执行到LoggingHandler.bind
方法,这里主要是打日志
public class LoggingHandler extends ChannelDuplexHandler {
@Override
public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception {
if (logger.isEnabled(internalLevel)) {
logger.log(internalLevel, format(ctx, "BIND", localAddress));
}
ctx.bind(localAddress, promise);
}
}
再执行HeadContext.bind
方法
public class DefaultChannelPipeline implements ChannelPipeline {
final class HeadContext extends AbstractChannelHandlerContext
implements ChannelOutboundHandler, ChannelInboundHandler {
@Override
public void bind(
ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) {
// unsafe是io.netty.channel.nio.AbstractNioMessageChannel$NioMessageUnsafe
unsafe.bind(localAddress, promise);
}
}
}
进入NioMessageUnsafe.bind
方法
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
protected abstract class AbstractUnsafe implements Unsafe {
@Override
public final void bind(final SocketAddress localAddress, final ChannelPromise promise) {
assertEventLoop();
// 忽略......
boolean wasActive = isActive();
try {
// key,绑定地址
// 这里其实是调用NioServerChannel的doBind方法
doBind(localAddress);
} catch (Throwable t) {
safeSetFailure(promise, t);
closeIfClosed();
return;
}
if (!wasActive && isActive()) {
// 成功激活,调用pipeline.fireChannelActive()方法
invokeLater(new Runnable() {
@Override
public void run() {
pipeline.fireChannelActive();
}
});
}
safeSetSuccess(promise);
}
}
}
进入NioServerChannel
的doBind
方法
public class NioServerSocketChannel extends AbstractNioMessageChannel
implements io.netty.channel.socket.ServerSocketChannel {
@SuppressJava6Requirement(reason = "Usage guarded by java version check")
@Override
protected void doBind(SocketAddress localAddress) throws Exception {
// 根据不同的JDK版本调用不同的方法
if (PlatformDependent.javaVersion() >= 7) {
// 我使用的是JDK8
// 调用java.nio.channels.ServerSocketChannel的bind方法
javaChannel().bind(localAddress, config.getBacklog());
} else {
javaChannel().socket().bind(localAddress, config.getBacklog());
}
}
}
可以看到,doBind0()
最后也是通过Java原生java.nio.channels.ServerSocketChannel
的bind()
方法来实现的。
总结
-
initAndRegister (),初始化。
-
通过反射创建
NioServerSocketChannel
,有下面几个变量- ch,
java.nio.channels.ServerSocketChannel
,Java NIO中的类 - readInterestOp,记录要监听的事件为:
SelectionKey.OP_ACCEPT
- unsafe,
io.netty.channel.nio.AbstractNioMessageChannel.NioMessageUnsafe
- pipeline,
DefaultChannelPipeline
,这是一个双向链表,默认链为:HeadContext<=>TailContext
- ch,
-
初始化
NioServerSocketChannel
这里主要是往
NioServerSocketChannel
的pipeline
中添加了一个ChannelInitializer
。此时的
ChannelPipeline
链条为:HeadContext<=>ChannelInitializer<=>TailContext
-
从线程组中(bossGroup)选了一个
NioEventLoop
-
此时
NioServerSocketChannel
就绑定了一个NioEventLoop
-
往这个
NioEventLoop
提交了一个异步任务[①]io.netty.channel.AbstractChannel.AbstractUnsafe#register0
。
异步任务的功能:将
NioServerSocketChannel
中的java.nio.channels.ServerSocketChannel
与NioEventLoop
的Selector
绑定。然后执行pipeline.invokeHandlerAddedIfNeeded()
方法。这里会触发ChannelInitializer
执行initChannel
方法,该方法会把第6步设置的handler添加到ChannelPipeline
,然后将自己从ChannelPipeline
移除。最后还往NioEventLoop
添加了一个异步任务[②],异步任务是往ChannelPipeline
添加ServerBootstrapAcceptor
。 -
-
-
doBind0绑定监听端口
往
NioEventLoop
添加了一个异步任务[③],异步任务的功能:通过Java NIO中的java.nio.channels.ServerSocketChannel
绑定本地端口。
需要注意上面提交的三个异步任务是按顺序执行的,因为NioEventLoop
里面只有一个线程执行任务队列里面的任务。
第①个任务执行完,此时ChannelPipeline
为:HeadContext<=>LoggineHandler<=>TailContext
第②个异步执行完,
此时ChannelPipeline
为:HeadContext<=>LoggineHandler<=>ServerBootstrapAcceptor<=>TailContext
首次往NioEventLoop
里面提交任务会触发NioEventLoop#run
方法执行,这个方法里面是一个死循环,里面负责监听Selector
上的IO事件和执行提交进来的异步任务。
重要组件说明
ChannelHandler
ChannelHandler
是核心业务处理接口,用于处理或拦截IO
事件,并将其转发到ChannelPipeline
中的下一个ChannelHandler
,运用的是责任链设计模式。
ChannelHandler
分为入站和出站两种:ChannelInboundHandler
和ChannelOutboundHandler
,一般不建议直接实现这两个接口,而是它们的抽象类:
SimpleChannelInboundHandler
:处理入站事件,它可以帮我们做资源的自动释放等操作。不建议直接使用ChannelInboundHandlerAdapter
。ChannelOutboundHandlerAdapter
:处理出站事件。ChannelDuplexHandler
:既可以处理入站也可以处理出站。
ChannelHandlerContext
默认实现DefaultChannelHandlerContext
,里面有ChannelHandler
和ChannelPipeline
的引用。
往ChannelPipeline
中的节点就是一个个ChannelHandlerContext
。
ChannelPipeline
ChannelPipeline
是 ChannelHandler
的集合,它负责处理和拦截入站和出站的事件和操作,每个Channel
都有一个ChannelPipeline
与之对应,会自动创建。
ChannelPipeline
中存储的是ChannelHandlerContext
链,通过这个链把ChannelHandler
连接起来。
- 一个
Channel
对应一个ChannelPipeline
- 一个
ChannelPipeline
包含一条双向的ChannelHandlerContext
链 - 一个
ChannelHandlerContext
中包含一个ChannelHandler
- 一个
Channel
会绑定到一个EventLoop
上 - 一个
NioEventLoop
维护了一个Selector
(使用的是 Java 原生的Selector
) - 一个
NioEventLoop
相当于一个线程