初始化
在网络编程 - 初识Netty中,我们看到了客户端Bootstrap调用channel(NioSocketChannel.class)
来传递所要初始化的Channel对象。
AbstractBootstrap类,可以看到传递的是ReflectiveChannelFactory,一个Channel的工厂类,赋值给Bootstrap的channelFactory。
public B channel(Class<? extends C> channelClass) {
if (channelClass == null) {
throw new NullPointerException("channelClass");
}
return channelFactory(new ReflectiveChannelFactory<C>(channelClass));
}
ReflectiveChannelFactory实现了ChannelFactory接口和newChannel方法,这个newChannel方法,会通过传过来的clazz创建一个Channel。这个方法的调用,在Bootstrap的connect()
方法中,后面会调用initAndRegister()
方法,Bootstrap先暂且略过,我们看看Channel是怎么初始化的,初始化又做了哪些事情。
public T newChannel() {
try {
// 这边调用NioSocketChannel的构造方法
return clazz.getConstructor().newInstance();
} catch (Throwable t) {
throw new ChannelException("Unable to create Channel from class " + clazz, t);
}
}
NioSocketChannel
public NioSocketChannel() {
// DEFAULT_SELECTOR_PROVIDER是SelectorProvider.provider()
this(DEFAULT_SELECTOR_PROVIDER);
}
public NioSocketChannel(SelectorProvider provider) {
// 通过SelectorProvider获取NIO的SocketChannel
this(newSocket(provider));
}
private static SocketChannel newSocket(SelectorProvider provider) {
try {
return provider.openSocketChannel();
} catch (IOException e) {
throw new ChannelException("Failed to open a socket.", e);
}
}
public NioSocketChannel(SocketChannel socket) {
this(null, socket);
}
public NioSocketChannel(Channel parent, SocketChannel socket) {
super(parent, socket);
// NioSocketChannel的属性设置
config = new NioSocketChannelConfig(this, socket.socket());
}
AbstractNioByteChannel
protected AbstractNioByteChannel(Channel parent, SelectableChannel ch) {
// 关注OP_READ事件
super(parent, ch, SelectionKey.OP_READ);
}
AbstractNioChannel
protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
super(parent);
this.ch = ch;
this.readInterestOp = readInterestOp;
try {
// 设置非阻塞
ch.configureBlocking(false);
} catch (IOException e) {
// 异常处理,关闭channel并抛异常,代码略
}
}
AbstractChannel
protected AbstractChannel(Channel parent) {
this.parent = parent;
id = newId();
// 创建一个NioSocketChannel.NioSocketChannelUnsafe的内部类对象
unsafe = newUnsafe();
// 创建一个Pipeline,并把当前的Channel赋值给Pipeline
pipeline = newChannelPipeline();
}
至此,Channel已经创建好了,在其中,他也创建了一个unsafe对象、Pipeline对象以及NioSocketChannelConfig对象。
unsafe类图如下,可以看出,Channel中与socket交互的,其实就是这个unsafe类。
ChannelPipeline这个类,后面再详细的讲。
注册
Channel初始化完成后,开始注册到EventLoop。
在AbstractBootstrap的initAndRegister方法中,初始化Channel后,开始执行ChannelFuture regFuture = config().group().register(channel)
。
MultithreadEventLoopGroup,这个next,就是通过chooserFactory.newChooser
得到的chooser,根据不同的策略来获取EventLoop。也就是说,这个register,其实就是注册到EventLoop中。
public ChannelFuture register(Channel channel) {
return next().register(channel);
}
SingleThreadEventLoop,先是创建DefaultChannelPromise,这边传递两个参数,一个是channel,一个是this,这个this,就是当前的EventLoop,所以Promise保持了他们两个的关系。再调用register方法时,调用unsafe的register方法。
public ChannelFuture register(Channel channel) {
return register(new DefaultChannelPromise(channel, this));
}
public ChannelFuture register(final ChannelPromise promise) {
ObjectUtil.checkNotNull(promise, "promise");
promise.channel().unsafe().register(this, promise);
return promise;
}
AbstractChannel.AbstractUnsafe,判断当前调用线程是否是支撑 EventLoop 的线程,如果是直接调用register0,否则,加入到队列。这样的好处,就是减少了线程的上下文切换导致的性能消耗。eventLoop的execute方法参见之前的文章。
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;
}
// 赋值eventLoop,register0方法会用到
AbstractChannel.this.eventLoop = eventLoop;
// 如果当前调用线程正是支撑 EventLoop 的线程,那么直接调用register0,否则,加入到队列
if (eventLoop.inEventLoop()) {
register0(promise);
} else {
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);
}
}
}
最终的注册方法。javaChannel()返回的是初始化的provider.openSocketChannel()
,eventLoop()返回的是上面register方法赋值的eventLoop,通过SelectableChannel的register方法,把Channel的SocketChannel注册到eventLoop的Selector中。
private void register0(ChannelPromise promise) {
// 部分代码略
doRegister();
// 部分代码略
}
protected void doRegister() throws Exception {
boolean selected = false;
for (;;) {
try {
selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
return;
} catch (CancelledKeyException e) {
// 部分代码略
}
}
}
Channel的生命周期
- ChannelUnregistered:表示Channel刚刚创建,还没注册到eventLoop,registered的值为false。
- ChannelRegistered:表示Channel注册到eventLoop。执行完
doRegister()
方法,把registered的值设为false - ChannelActive:表示Channel 处于活动状态(已经连接到它的远程节点)。它现在可以接收和发送数据了,参考下面
isActive()
方法。 - ChannelInactive:表示Channel 没有连接到远程节点。
public boolean isActive() {
SocketChannel ch = javaChannel();
return ch.isOpen() && ch.isConnected();
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。