目录
服务器示例代码:
// 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();
if (sslCtx != null) {
p.addLast(sslCtx.newHandler(ch.alloc()));
}
//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();
分析EventLoopGroup 对象
分析默认线程数
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
进入无参构造函数一直进入:
super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
无参数nThreads
默认为0
,因此nThreads==DEFAULT_EVENT_LOOP_THREADS
private static final int DEFAULT_EVENT_LOOP_THREADS;
static {
DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(
"io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));
}
发现DEFAULT_EVENT_LOOP_THREADS
的默认值为cpu
核数的两倍。
分析 EventLoopGroup 的过程
继续跟踪构造函数,发现抽象类 MultithreadEventExecutorGroup
的构造器方法MultithreadEventExecutorGroup
,才是 NioEventLoopGroup
真正的构造方法。
protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
EventExecutorChooserFactory chooserFactory, Object... args) {
//如果传入的执行器是空的,则采用默认的线程工厂new DefaultThreadFactory
//和默认的执行器ThreadPerTaskExecutor(是一个线程池)
if (executor == null) {
executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
}
//创建指定线程数的执行器数组,EventExecutor也是一个线程池
children = new EventExecutor[nThreads];
//初始化线程数组
for (int i = 0; i < nThreads; i ++) {
boolean success = false;
try {
//创建new NioEventLoop并添加到执行器数组中,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);
}
}
};
//为每一个单例线程池NioEventLoop,添加一个关闭监听器
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
,使用 Netty
默认的线程工厂DefaultThreadFactory
,创建一个默认的 ThreadPerTaskExecutor
作为执行器。
2)根据传入的线程数(CPU*2
)创建一个线程池(单例线程池)数组EventExecutor
。
3)循环填充数组中的元素,创建new NioEventLoop
并添加到执行器数组中。如果异常,则关闭所有的单例线程池NioEventLoop
。NioEventLoop
本身就是线程池。
4)根据线程选择工厂创建一个 线程选择器。
5)为每一个单例线程池添加一个关闭监听器。
6)将所有的单例线程池添加到一个 HashSet
中。
ServerBootstrap 创建和构造过程
ServerBootstrap 是个空构造,但是有默认的成员变量
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;
分析一下 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(serverHandler);
}
});
说明:
1)链式调用:group
方法,将bossGroup
和workerGroup
传入,bossGroup
赋值给parentGroup
属性,workerGroup
赋值给 childGroup
属性
2)channel
方法传入NioServerSocketChannel.class
对象。会根据这个 class
,通过反射创建 NioServerSocketChannel
的构造器对象并把这个对象封装到ChannelFactory
中,返回ServerBootstrap
3)option
方法传入 TCP
参数,放在一个ConcurrentHashMap
中。
4)handler
方法传入一个 handler
中,这个hanlder
只专属于 ServerSocketChannel
而不是 SocketChannel(客户端那个)
5)childHandler
传入一个 hanlder
,这个handler
将会在每个客户端连接的时候调用。供 SocketChannel
使用
绑定端口的分析
服务器就是在这个bind
方法里启动完成的
ChannelFuture f = b.bind(PORT).sync();
public ChannelFuture bind(SocketAddress localAddress) {
validate();
return doBind(ObjectUtil.checkNotNull(localAddress, "localAddress"));
}
核心代码doBind
核心是两个方法 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;
}
}
分析说明 initAndRegister
final ChannelFuture initAndRegister() {
Channel channel = null;
// ...
channel = channelFactory.newChannel();
//...
init(channel);
//...
ChannelFuture regFuture = config().group().register(channel);
//...
return regFuture;
}
initAndRegister里面做了三件事情
- new一个channel
- init这个channel
- 将这个channel 注册到某个对象
new一个channel
我们发现这条channel
是通过一个 channelFactory new
出来的,跟进入最终是调用到 ReflectiveChannelFactory.newChannel()
方法
public T newChannel() {
try {//这个构造器就是之前创建的
return constructor.newInstance();
} catch (Throwable t) {
throw new ChannelException("Unable to create Channel from class " + constructor.getDeclaringClass(), t);
}
}
通过反射的方式来创建一个对象,而这个class
就是我们在ServerBootstrap
中传入的NioServerSocketChannel.class
接下来我们就可以将重心放到 NioServerSocketChannel
的默认构造函数。
private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();
public NioServerSocketChannel() {
this(newSocket(DEFAULT_SELECTOR_PROVIDER));
}
private static ServerSocketChannel newSocket(SelectorProvider provider) {
//...
return provider.openServerSocketChannel();
}
通过SelectorProvider.openServerSocketChannel()
创建一条server
端channel
,然后进入到以下方法:
public NioServerSocketChannel(ServerSocketChannel channel) {
super(null, channel, SelectionKey.OP_ACCEPT);
//创建一个NioServerSocketChannelConfig
//主要用于向外展示NioServerSocketChannel的一些配置信息
config = new NioServerSocketChannelConfig(this, javaChannel().socket());
}
protected AbstractNioMessageChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
super(parent, ch, readInterestOp);
}
这个readInterestOp
变量是SelectionKey.OP_ACCEPT
枚举的值,这里我们要加深下印象,后面会用到这个变量:
protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
super(parent);
this.ch = ch;
this.readInterestOp = readInterestOp;
try {
ch.configureBlocking(false);
} catch (IOException e) {
。。。。
}
NioServerSocketChannel
的最终构造,主要可以分为3点:
protected AbstractChannel(Channel parent) {
this.parent = parent;
id = newId();
unsafe = newUnsafe();//空构造,不看
pipeline = newChannelPipeline();
}
- 调用newId(),生成一个全局Id,这个我们不讲解
- 调用newUnsafe(),生成NioMessageUnsafe对象,这个对象很关键,包括后面的NioServerSocketChannel往Selector注册ACCEPT事件、NioServerSocketChannel绑定端口都需要用到这个对象。
- 调用newChannelPipeline(),生成DefaultChannelPipeline对象,这个ChannelPipeline我们很熟悉,就是Netty非常出名的调用链对象。
继续往下看newChannelPipeline
():
protected DefaultChannelPipeline newChannelPipeline() {
return new DefaultChannelPipeline(this);
}
protected DefaultChannelPipeline(Channel channel) {
this.channel = ObjectUtil.checkNotNull(channel, "channel");
succeededFuture = new SucceededChannelFuture(channel, null);
voidPromise = new VoidChannelPromise(channel, true);
tail = new TailContext(this);//TailContext为AbstractChannelHandlerContext
head = new HeadContext(this);//HeadContext为AbstractChannelHandlerContext
head.next = tail;
tail.prev = head;
}
由上面代码我们可以了解到ChannelPipeline
的构造过程,总结为以下几点
- 每个
channelpipeline
都和一个channel
绑定,不管是NioServerSocketChannel
还是NioSocketChannel
。当然我们这里的这个channel
是NioServerSocketChannel
ChannelPipeline
它是一个双向循环链表结构,链表中的元素为AbstractChannelHandlerContext
对象,那为什么我们往ChannelPipeline
中添加的是ChannelHandler
对象?因为每次用户添加ChannelHandler
对象的时候,Netty
会自动把ChannelHandler
包装成AbstractChannelHandlerContext
对象,在插入链表中。- 初始化过程中,会自动创建头结点和尾结点,分别为
HeadContext
和TailContext
此时channelpipeline
的双向链表结构如下:
总结:创建channel主要干了什么事情。
1.使用channelFactory
创建channel
;
2.设置相关属性,如:生成一个全局Id,创建管道
3.管道是双向链表结构,初始化的时候自动添加头结点和为节点,都是ChannelHandlerContext
到此为止NioServerSocketChannel
的对象构造完毕。
初始化channel
void init(Channel channel) {
//设置option和attr,先调用options0()以及attrs0()
//然后将得到的options和attrs注入到channelConfig或者channel中
setChannelOptions(channel, options0().entrySet().toArray(newOptionArray(0)), logger);
setAttributes(channel, attrs0().entrySet().toArray(newAttrArray(0)));
//获取channel的pipeline
ChannelPipeline p = channel.pipeline();
final EventLoopGroup currentChildGroup = childGroup;
final ChannelHandler currentChildHandler = childHandler;
//设置新接入channel的option和attr
final Entry<ChannelOption<?>, Object>[] currentChildOptions =
childOptions.entrySet().toArray(newOptionArray(0));
final Entry<AttributeKey<?>, Object>[] currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(0));
//调用pipeline.addLast()往pipeline添加一个ChannelInitializer对象,
//ChannelInitializer对象的initChannel()并不会马上执行,什么时候执行,后面会说
p.addLast(new ChannelInitializer<Channel>() {
@Override
public void initChannel(final Channel ch) {
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));
}
});
}
});
}
我们看一下pipeline
的addLast
()方法:
@Override
public final ChannelPipeline addLast(ChannelHandler... handlers) {
return addLast(null, handlers);
}
public final ChannelPipeline addLast(EventExecutorGroup executor, ChannelHandler... handlers) {
for (ChannelHandler h: handlers) {
if (h == null) {
break;
}
addLast(executor, null, h);
}
return this;
}
@Override
public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
final AbstractChannelHandlerContext newCtx;
synchronized (this) {
checkMultiplicity(handler);
//把handler包装成AbstractChannelHandlerContext对象
newCtx = newContext(group, filterName(name, handler), handler);
//把上面生成的AbstractChannelHandlerContext对象添加到双向链表中
addLast0(newCtx);
//如果该channel还没有注册,那么调用callHandlerCallbackLater(newCtx,true),延迟执行该
//AbstractChannelHandlerContext的handlerAdded()方法,即把该AbstractChannelHandlerContext加入
//一个单链表中,那么一旦该channel注册到NioEventLoop中,就会马上执行该单链表上的
//AbstractChannelHandlerContext的handlerAdded方法(很显然,我们现在channel还没有注册,所以会加入到单链表中)
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),即执行AbstractChannelHandlerContext的handlerAdded()方法
//为什么上面说延迟执行handlerAdded(),等到注册完后在执行,这里又说要执行handlerAdded()?因为有
//些AbstractChannelHandlerContext的handlerAdded()是不需要注册后才执行的(也就是不需要延迟执
//行)。因为我们这里添加的是ChannelInitializer对象,我们看下ChannelInitializer源码便清楚。
callHandlerAdded0(newCtx);
return this;
}
说明:
- 调用newCtx = newContext(group, filterName(name, handler),
handler),把handler包装成AbstractChannelHandlerContext对象 - 调用addLast0(newCtx),把上面生成的AbstractChannelHandlerContext对象添加到双向链表中
private void addLast0(AbstractChannelHandlerContext newCtx) {
AbstractChannelHandlerContext prev = tail.prev;
newCtx.prev = prev;
newCtx.next = tail;
prev.next = newCtx;
tail.prev = newCtx;
}
- 如果该channel还没有注册,那么调用callHandlerCallbackLater(newCtx,true),延迟执行该AbstractChannelHandlerContext的handlerAdded()方法,即把该AbstractChannelHandlerContext加入一个单链表中,那么一旦该channel注册到NioEventLoop中,就会马上执行该单链表上的AbstractChannelHandlerContext的handlerAdded方法(很显然,我们现在channel还没有注册,所以会加入到单链表中)
if (!registered) {
newCtx.setAddPending();
callHandlerCallbackLater(newCtx, true);
return this;
}
private void callHandlerCallbackLater(AbstractChannelHandlerContext ctx, boolean added) {
assert !registered;
PendingHandlerCallback task = added ? new PendingHandlerAddedTask(ctx) : new PendingHandlerRemovedTask(ctx);
// pendingHandlerCallbackHead是单链表结构
PendingHandlerCallback pending = pendingHandlerCallbackHead;
if (pending == null) {
pendingHandlerCallbackHead = task;
} else {
// Find the tail of the linked-list.
while (pending.next != null) {
pending = pending.next;
}
pending.next = task;
}
}
- 调用callHandlerAdded0(newCtx),即执行AbstractChannelHandlerContext的handlerAdded()方法
为什么上面说延迟执行handlerAdded(),等到注册完后在执行,这里又说要执行handlerAdded()?因为有些AbstractChannelHandlerContext的handlerAdded()是不需要注册后才执行的(也就是不需要延迟执行)。因为我们这里添加的是ChannelInitializer对象,我们看下ChannelInitializer源码便清楚。
private void callHandlerAdded0(final AbstractChannelHandlerContext ctx) {
try {
ctx.handler().handlerAdded(ctx);
ctx.setAddComplete();
} catch (Throwable t) {
...省略
}
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
if (ctx.channel().isRegistered()) {
//很显然了,这里首先获取了channel,并且判断了该channel是否注册到NioEventLoop,
//很显然,目前来说还没有,所以initChannel(ctx)方法并没有执行。
initChannel(ctx);
}
}
那么此时pipeline中的数据结构如下图:
总结:
初始化管道主要做了啥
1.进行一些option的配置
2.进行一些attr的配置
3.调用pipeline.addLast()
往pipeline
添加一个ChannelInitializer
对象
到此为止channelpipe.addLast()
方法就分析完毕了,而且init(channel)
也走完了
将这个channel 注册到某个对象
ChannelFuture regFuture = config().group().register(channel);
这里创建了DefaultChannelPromise
对象,很显然等一下会使用到异步调用:
SingleThreadEventLoop.java
public ChannelFuture register(Channel channel) {
return register(new DefaultChannelPromise(channel, this));
}
//继续根据,省略中间一些步骤
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设置NioEventLoop,标记该Channel是由那个NioEventLoop来管理的
AbstractChannel.this.eventLoop = eventLoop;
//判断当前线程是否在NioEventLoop线程中
if (eventLoop.inEventLoop()) {
//如果在,那么直接在同步调用register0(promise)方法
register0(promise);
} else {
try {
//如果不在,那么把register0(promise)方法包装一个Task放入NioEventLoop的队列中
//让NioEventLoop线程池异步执行。
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);
}
}
}
很显然,当前我们还在Main
线程中,不在NioEventLoop
这个线程中,所以它会先返回结果,在异步执行register0(promise)
因为是异步执行的register0(promise)
方法,所以我们暂且先不跟这个方法,我们先回到调用的起点,也就是initAndRegister
()中
final ChannelFuture initAndRegister() {
Channel channel = null;
// ...
channel = channelFactory.newChannel();
//...
init(channel);
//...
ChannelFuture regFuture = config().group().register(channel);
//...
return regFuture;
}
那么现在initAndRegister
()调用也走完了,返回ChannelFuture
到doBind
(),这个regFuture
就是异步执行register0(promise)
中的promise
。
private ChannelFuture doBind(final SocketAddress localAddress) {
final ChannelFuture regFuture = initAndRegister();
final Channel channel = regFuture.channel();
if (regFuture.cause() != null) {
return regFuture;
}
//判断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;
}
}
调用完initAndRegister()方法后
- 首先判断该
future
,是否isDone
(),如果是,那么直接调用doBind0(regFuture, channel,localAddress, promise)
; - 如果不是,那么往
future
中加入一个监听器,为了好记我们称它为"RegisterListener
",在监听器里面去调用doBind0(regFuture, channel, localAddress, promise)
;
我们这分析的时候future
是没有完成的,它会走监听器,具体什么时候调用监听器呢?我们这时候回到刚刚异步执行的register0(promise)
方法,这个方法在AbstractUnsafe
类下,AbstractUnsafe
是AbstractChannel
的内部类,所以AbstractChannel
类的属性,在AbstractUnsafe
类下也可以访问。
AbstractUnsafe.java
private void register0(ChannelPromise promise) {
try {
if (!promise.setUncancellable() || !ensureOpen(promise)) {
return;
}
boolean firstRegistration = neverRegistered;
//往NioEventLoop的Selector注册。
doRegister();
neverRegistered = false;
//把channel的registered变量标记为true
registered = true;
//之前我们调用pipeline.addLast()讲的延迟调用,一旦注册后,
//就立马执行单链表上的channelHandler,那么这个单链表上的channelHandler就是在这依次被调用
pipeline.invokeHandlerAddedIfNeeded();
//触发promise的监听器的operationComplete()方法。
safeSetSuccess(promise);
//触发pipeline中的inboundchannelHandler的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.
if (isActive()) {
if (firstRegistration) {
//获取channel的绑定状态,如果已经绑定端口,而且是第一次注册,
//那么调用pipeline.fireChannelActive();
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);
}
}
1、doRegister()
AbstractNioChannel.java
@Override
protected void doRegister() throws Exception {
boolean selected = false;
for (;;) {
try {
selectionKey = javaChannel().register(eventLoop().selector, 0, this);
return;
} catch (CancelledKeyException e) {
。。。
}
}
}
- 这里注册的事件是0,即什么事件也不监听。
- 这里可能会有疑问?为什么不直接注册ACCEPT事件,因为目前来说channel还没有绑定端口,那么现在注册ACCEPT事件也没什么意义。
2、pipeline.invokeHandlerAddedIfNeeded();
DefaultChannelPipeline.java
final void invokeHandlerAddedIfNeeded() {
assert channel.eventLoop().inEventLoop();
if (firstRegistration) {
firstRegistration = false;
callHandlerAddedForAllHandlers();
}
}
DefaultChannelPipeline.java
private void callHandlerAddedForAllHandlers() {
final PendingHandlerCallback pendingHandlerCallbackHead;
synchronized (this) {
assert !registered;
// This Channel itself was registered.
registered = true;
pendingHandlerCallbackHead = this.pendingHandlerCallbackHead;
// Null out so it can be GC'ed.
this.pendingHandlerCallbackHead = null;
}
// This must happen outside of the synchronized(...) block as otherwise handlerAdded(...) may be called while
// holding the lock and so produce a deadlock if handlerAdded(...) will try to add another handler from outside
// the EventLoop.
PendingHandlerCallback task = pendingHandlerCallbackHead;
while (task != null) {
task.execute();
task = task.next;
}
}
PendingHandlerAddedTask.java
@Override
void execute() {
EventExecutor executor = ctx.executor();
if (executor.inEventLoop()) {
//里面就是执行
callHandlerAdded0(ctx);
} else {
try {
executor.execute(this);
} catch (RejectedExecutionException e) {
if (logger.isWarnEnabled()) {
logger.warn(
"Can't invoke handlerAdded() as the EventExecutor {} rejected it, removing handler {}.",
executor, ctx.name(), e);
}
remove0(ctx);
ctx.setRemoved();
}
}
}
private void callHandlerAdded0(final AbstractChannelHandlerContext ctx) {
try {
ctx.handler().handlerAdded(ctx);
ctx.setAddComplete();
} catch (Throwable t) {
...省略
}
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
if (ctx.channel().isRegistered()) {
//很显然了,这里首先获取了channel,并且判断了该channel是否注册到NioEventLoop,
//很显然,目前来说注册了,所以initChannel(ctx)方法被执行。
initChannel(ctx);
}
}
还记得我们往单链表pendingHandlerCallbackHead
添加了一个ChannelInitializer
对象,我们回顾一下
ServerBootstrap.java init()中一个片段
p.addLast(new ChannelInitializer<Channel>() {
@Override
public void initChannel(Channel ch) throws Exception {
final ChannelPipeline pipeline = ch.pipeline();
//首先获取handler
ChannelHandler handler = config.handler();
if (handler != null) {
//添加handler
pipeline.addLast(handler);
}
//往管理channel的NioEventLoop的队列中插入一个Task
ch.eventLoop().execute(new Runnable() {
@Override
public void run() {
pipeline.addLast(new ServerBootstrapAcceptor(
currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}
});
}
});
那么此时就会执行ChannelInitializer
对象的handlerAdded
()方法,并且因为已经注册了,那么就会执行initChannel(ctx)
方法
- 首先获取
handler
,即是最开始模板代码中我们调用ServerBootstrap.handler(new
LoggingHandler())。 - 然后往管理
channel
的NioEventLoop
的队列中插入一个Task
。
那么此时pipeline
中数据结构为,如下:
3、然后执行safeSetSuccess(promise)
;,即通知往promise
自己注册的所有监听器,那么这时候我们要回到AbstractBoostrap
的doBind(final SocketAddress localAddress)
方法中
AbstractBoostrap.java doBind(final SocketAddress localAddress) 的一个片段
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();
doBind0(regFuture, channel, localAddress, promise);
}
}
});
那么这时候会执行operationComplete()
方法,然后调用 doBind0(regFuture, channel, localAddress, promise);
AbstractBoostrap.java
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()) {
channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
} else {
promise.setFailure(regFuture.cause());
}
}
});
}
这里往channel
的NioEventLoop
队列里插入一个Task
,因为NioEventLoop
是个单线程线程池,因为该NioEventLoop
正在执行register0(promise)
这个方法,所以这个Task
不会立马被执行,而是等register0(promise)
执行完后才执行。所以我们回到register0(promise)
方法。
4、pipeline.fireChannelRegistered();
调用pipleline中的双向链表中的inbound Handler
的channelRegistered()
方法
此时register0(promise)
就执行完毕了,刚刚我们往负责Channel
的NioEventLoop
的队列中丢入了一个Task
,那么现在它会被执行。
AbstractBoostrap.java
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()) {
channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
} else {
promise.setFailure(regFuture.cause());
}
}
});
}
调用了channel.bind(localAddress, promise)
AbstractChannel.java
@Override
public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
return pipeline.bind(localAddress, promise);
}
DefaultChannelPipeline.java
@Override
public final ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
return tail.bind(localAddress, promise);
}
AbstractChannelHandlerContext.java
@Override
public ChannelFuture bind(final SocketAddress localAddress, final ChannelPromise promise) {
if (localAddress == null) {
throw new NullPointerException("localAddress");
}
if (!validatePromise(promise, false)) {
// cancelled
return promise;
}
//首先调用findContextOutbound(),从链表的的尾部往前找属于outbound的
final AbstractChannelHandlerContext next = findContextOutbound();
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
//然后调用AbstractChannelHandlerContext 的invokeBind(localAddress, promise);
next.invokeBind(localAddress, promise);
} else {
safeExecute(executor, new Runnable() {
@Override
public void run() {
next.invokeBind(localAddress, promise);
}
}, promise, null);
}
return promise;
}
- 首先调用findContextOutbound(),从链表的的尾部往前找属于outbound的AbstractChannelHandlerContext
- 然后调用AbstractChannelHandlerContext 的invokeBind(localAddress, promise);
AbstractChannelHandlerContext.java
private AbstractChannelHandlerContext findContextOutbound() {
AbstractChannelHandlerContext ctx = this;
do {
ctx = ctx.prev;
} while (!ctx.outbound);
return ctx;
}
private void invokeBind(SocketAddress localAddress, ChannelPromise promise) {
if (invokeHandler()) {
try {
((ChannelOutboundHandler) handler()).bind(this, localAddress, promise);
} catch (Throwable t) {
notifyOutboundHandlerException(t, promise);
}
} else {
bind(localAddress, promise);
}
}
直接调用handler的bind()方法
我们首先回顾一下当前pipeline中的双向链表:
这里比较关键的属于outbound的channelHandler为HeadContext,我们直接看HeadContext的bind()方法:
HeadContext.java
@Override
public void bind(
ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise)
throws Exception {
unsafe.bind(localAddress, promise);
}
AbstractUnsafe.java
@Override
public final void bind(final SocketAddress localAddress, final ChannelPromise promise) {
....
boolean wasActive = isActive();
try {
doBind(localAddress);
} catch (Throwable t) {
safeSetFailure(promise, t);
closeIfClosed();
return;
}
if (!wasActive && isActive()) {
invokeLater(new Runnable() {
@Override
public void run() {
pipeline.fireChannelActive();
}
});
}
safeSetSuccess(promise);
}
这个方法是整个Netty服务端绑定端口的最核心的方法
- doBind(localAddress);绑定端口
- pipeline.fireChannelActive();往pipeline中传递channelActive事件
1、 doBind(localAddress);
NioServerSocketChannel.java
@Override
protected void doBind(SocketAddress localAddress) throws Exception {
if (PlatformDependent.javaVersion() >= 7) {
javaChannel().bind(localAddress, config.getBacklog());
} else {
javaChannel().socket().bind(localAddress, config.getBacklog());
}
}
这里很熟悉了,用到了NIO的API,根据JDK版本
- 如果>=7,ServerSocketChannel.bind(SocketAddress,config.getBacklog())
- 否则,ServerSocketChannel.socket().bind(SocketAddress,config.getBacklog())
2、pipeline.fireChannelActive();往pipeline中传递channelActive事件
DefaultChannelPipeline.java
@Override
public final ChannelPipeline fireChannelActive() {
AbstractChannelHandlerContext.invokeChannelActive(head);
return this;
}
这里的head是双向链表的头指针,即为HeadContext
AbstractChannelHandlerContext.java
static void invokeChannelActive(final AbstractChannelHandlerContext next) {
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
next.invokeChannelActive();
} else {
executor.execute(new Runnable() {
@Override
public void run() {
next.invokeChannelActive();
}
});
}
}
private void invokeChannelActive() {
if (invokeHandler()) {
try {
((ChannelInboundHandler) handler()).channelActive(this);
} catch (Throwable t) {
notifyHandlerException(t);
}
} else {
fireChannelActive();
}
}
直接调用HeadContext
的channelActive
()方法
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelActive()
readIfIsAutoRead();
}
首先把channelActive
事件往下传递,因为其他channelHandler
都不是关键,我们就不往下看了,然后调用readIfIsAutoRead
();
HeadContext.java
private void readIfIsAutoRead() {
if (channel.config().isAutoRead()) {
channel.read();
}
}
AbstractChannel.java
@Override
public Channel read() {
pipeline.read();
return this;
}
DefaultChannelPipeline.java
@Override
public final ChannelPipeline read() {
tail.read();
return this;
}
@Override
public ChannelHandlerContext read() {
final AbstractChannelHandlerContext next = findContextOutbound();
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
next.invokeRead();
} else {
Runnable task = next.invokeReadTask;
if (task == null) {
next.invokeReadTask = task = new Runnable() {
@Override
public void run() {
next.invokeRead();
}
};
}
executor.execute(task);
}
return this;
}
从双向链表的尾指针开始往前找outbound
的ChannelHandler
,然后调用ChannelHandler
的read
()方法
这里找到的最关键的ChannelHandler
就是HeadContext
,所以我们来看HeadContext
的read
()
HeadContext.java
@Override
public void read(ChannelHandlerContext ctx) {
unsafe.beginRead();
}
AbstractUnsafe.java
public final void beginRead() {
assertEventLoop();
if (!isActive()) {
return;
}
try {
doBeginRead();
} catch (final Exception e) {
invokeLater(new Runnable() {
@Override
public void run() {
pipeline.fireExceptionCaught(e);
}
});
close(voidPromise());
}
}
AbstractNioMessageChannel.java
@Override
protected void doBeginRead() throws Exception {
if (inputShutdown) {
return;
}
super.doBeginRead();
}
AbstractNioChannel.java
@Override
protected void doBeginRead() throws Exception {
// Channel.read() or ChannelHandlerContext.read() was called
final SelectionKey selectionKey = this.selectionKey;
if (!selectionKey.isValid()) {
return;
}
readPending = true;
final int interestOps = selectionKey.interestOps();
if ((interestOps & readInterestOp) == 0) {
selectionKey.interestOps(interestOps | readInterestOp);
}
}
OK,readInterestOp就是之前的SelectionKey.OP_ACCEPT的值,又是我们很熟悉的NIO的API,通过selectionKey .interestOps()注册一个ACCEPT事件。
到此为止,Netty服务端的绑定端口源码执行完毕。