0. java还要写到什么时候嘛…
// io.netty.bootstrap.AbstractBootstrap#doBind
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(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;
}
}
1. 直接进入主题
// io.netty.bootstrap.AbstractBootstrap#initAndRegister
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
// step into ...
// 从语义可知: Channel工厂会创建一个通道实例
// 工厂反射创建出channel(构造中维护了jdk的socketChannel)
// 本章节专注于这个方法
channel = channelFactory.newChannel();
// 初始化
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);
}
// group 指的是 bossGroup:EventLoopGroup(因此将进入MultithreadEventLoopGroup)
// 这里用脚可以想到:registry发生了:channel(IO)开始关联了线程模型
// 这里的unsafe被封装到了netty.Channel,作为内部接口
ChannelFuture regFuture = config().group().register(channel);
if (regFuture.cause() != null) {
if (channel.isRegistered()) {
channel.close();
} else {
channel.unsafe().closeForcibly();
}
}
// If we are here and the promise is not failed, it's one of the following cases:
// 1) If we attempted registration from the event loop, the registration has been completed at this point.
// i.e. It's safe to attempt bind() or connect() now because the channel has been registered.
// 2) If we attempted registration from the other thread, the registration request has been successfully
// added to the event loop's task queue for later execution.
// i.e. It's safe to attempt bind() or connect() now:
// because bind() or connect() will be executed *after* the scheduled registration task is executed
// because register(), bind(), and connect() are all bound to the same thread.
return regFuture;
}
1.1 回溯到channelFactory实例化的时候
发生再前面ServerBootstrap的构建过程中
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
// step into ...
.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(new EchoServerHandler());
}
});
ChannelFuture f = b.bind(EchoConstants.PORT_SERVER).sync();
f.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
// io.netty.bootstrap.AbstractBootstrap#channel
public B channel(Class<? extends C> channelClass) {
// 这里保存了传入的channel的Class,用于后续使用反射调用其构造器
// 在这里创建了通道的工厂(从命名可知:通过反射创建实例)实例,并赋值到了全局
return channelFactory(new ReflectiveChannelFactory<C>(
ObjectUtil.checkNotNull(channelClass, "channelClass")
));
}
1.2 ChannelFactory创建 Channel
1.2.1 调用Channel的构造器实例来创建Channel实例
public class ReflectiveChannelFactory<T extends Channel> implements ChannelFactory<T> {
private final Constructor<? extends T> constructor;
public ReflectiveChannelFactory(Class<? extends T> clazz) {
ObjectUtil.checkNotNull(clazz, "clazz");
try {
// 通道工厂实例化时,保存的是通道类的构造器的实例
this.constructor = clazz.getConstructor();
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Class " + StringUtil.simpleClassName(clazz) +
" does not have a public non-arg constructor", e);
}
}
@Override
public T newChannel() {
try {
// step into ...
// 调用其无参构造创建通道实例
return constructor.newInstance();
} catch (Throwable t) {
throw new ChannelException("Unable to create Channel from class " + constructor.getDeclaringClass(), t);
}
}
}
1.2.2 Channel、pipeline构造
值得注意的设计:
- jdk.channel 被封闭到 netty.channel 内部维护,并非继承关系
- pipeline 会在netty.channel构造过程中实例化,呈双向链表,此时并没有往里添加我们自定义的handler
// io.netty.channel.socket.nio.NioServerSocketChannel
public NioServerSocketChannel() {
// private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();
// 1. 获取selector作为socket的构造参数
// 2. 构造socket实例作为该channel(NioServerSocketChannel)的构造参数
// 注意:执行完 2 时,jdk.channel实例已经创建完成,维护在netty.channel内部
// 3. 执行channel的构造函数
this(newSocket(DEFAULT_SELECTOR_PROVIDER));
}
// java.nio.channels.spi.SelectorProvider#provider
// 1. 获取selector作为socket的构造参数
public static SelectorProvider provider() {
synchronized (lock) {
if (provider != null)
return provider;
return AccessController.doPrivileged(
new PrivilegedAction<SelectorProvider>() {
public SelectorProvider run() {
if (loadProviderFromProperty())
return provider;
if (loadProviderAsService())
return provider;
// 因为我们之前构造NioEventLoopGroup时,没有指定selectorProvider,所以会默认返回jdk默认的selector
provider = sun.nio.ch.DefaultSelectorProvider.create();
return provider;
}
});
}
}
// io.netty.channel.socket.nio.NioServerSocketChannel
// 2. 构造socket实例作为该channel(NioServerSocketChannel)的构造参数
private static ServerSocketChannel newSocket(SelectorProvider provider) {
try {
/**
* Use the {@link SelectorProvider} to open {@link SocketChannel} and so remove condition in
* {@link SelectorProvider#provider()} which is called by each ServerSocketChannel.open() otherwise.
*
* See <a href="https://github.com/netty/netty/issues/2308">#2308</a>.
*/
// 这里使用jdk默认的selector打开一个服务端的通道
return provider.openServerSocketChannel();
} catch (IOException e) {
throw new ChannelException(
"Failed to open a server socket.", e);
}
}
// io.netty.channel.socket.nio.NioServerSocketChannel
// 3. 执行channel的构造函数
public NioServerSocketChannel(ServerSocketChannel channel) {
// 4. 执行父类构造
// 看看这里的入参:
// null:netty.channel的父级通道
// channel:jdk.channel
// SelectionKey.OP_ACCEPT:selector轮询时的偏好事件
super(null, channel, SelectionKey.OP_ACCEPT);
// 这里掠过,无伤大雅,主要就是传递引用而已
config = new NioServerSocketChannelConfig(this, javaChannel().socket());
}
// io.netty.channel.nio.AbstractNioMessageChannel#AbstractNioMessageChannel
// 4. 执行父类构造
protected AbstractNioMessageChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
// step into ...
super(parent, ch, readInterestOp);
}
// io.netty.channel.nio.AbstractNioChannel#AbstractNioChannel
// 4. 执行父类构造
protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
super(parent);
this.ch = ch;
this.readInterestOp = readInterestOp;
try {
// 设置jdk.channel非阻塞
ch.configureBlocking(false);
} catch (IOException e) {
try {
ch.close();
} catch (IOException e2) {
logger.warn(
"Failed to close a partially initialized socket.", e2);
}
throw new ChannelException("Failed to enter non-blocking mode.", e);
}
}
// io.netty.channel.AbstractChannel#AbstractChannel(io.netty.channel.Channel)
// 4. 执行父类构造
protected AbstractChannel(Channel parent) {
this.parent = parent;
id = newId();
// 这里unsafe的概念类似sun的,但是不是一个类,netty自己搞的
// 实例化的是 DefaultServerUnsafe extends AbstractUnsafe
// 后面事件触发后,底层都会借助这个内部类
unsafe = newUnsafe();
// 6. 实例化1个pipeline,作为channel内部变量维护
// pipeline其实就是内部执行逻辑的1条双向执行链
// 链上主要netty默认初始化的head/tailContext 以及 我们自定义的handler
pipeline = newChannelPipeline();
}
// io.netty.channel.DefaultChannelPipeline#DefaultChannelPipeline
// 6. 实例化1个pipeline,作为channel内部变量维护
protected DefaultChannelPipeline(Channel channel) {
// pipeline持有了netty.channel的引用
this.channel = ObjectUtil.checkNotNull(channel, "channel");
succeededFuture = new SucceededChannelFuture(channel, null);
voidPromise = new VoidChannelPromise(channel, true);
// head/tailContext都持有了pipeline的引用
tail = new TailContext(this);
head = new HeadContext(this);
// 老司机都懂的双向链表结构
head.next = tail;
tail.prev = head;
}