应用代码
public static void start() throws Exception {
ServerBootstrap bootstrap = new ServerBootstrap();
EventLoopGroup boss = new NioEventLoopGroup();
EventLoopGroup work = new NioEventLoopGroup();
bootstrap.group(boss, work)
.handler(new LoggingHandler(LogLevel.DEBUG))
//重点看这句Channel
.channel(NioServerSocketChannel.class)
.childHandler(new HttpServerInitializer());
ChannelFuture f = bootstrap.bind(new InetSocketAddress(port)).sync();
...
源码
一、初始化ServerBootstrap的channelFactory属性
public B channel(Class<? extends C> channelClass) {
return channelFactory(new ReflectiveChannelFactory<C>(
ObjectUtil.checkNotNull(channelClass, "channelClass")
));
}
这里学习下一个工厂
ReflectiveChannelFactory
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 {
return constructor.newInstance();
} catch (Throwable t) {
throw new ChannelException("Unable to create Channel from class " + constructor.getDeclaringClass(), t);
}
}
@Override
public String toString() {
return StringUtil.simpleClassName(ReflectiveChannelFactory.class) +
'(' + StringUtil.simpleClassName(constructor.getDeclaringClass()) + ".class)";
}
}
解读一下:
ChannelFactory是一个泛型接口,定义了newChannel()方法,也就是ChannelFactory的实现类要有能力构造一个new Channel。
ReflectiveChannelFactory的泛型T是Channel的子类。也就是说ReflectiveChannelFactory支持实例化Channel的子类。比如NioServerScoketChannel。
而ReflectiveChannelFactory的构造方法中,将Channel类的无参构造方法,赋值给constructor属性。
在newChannel()方法中,通过反射调用constructor无参构造方法,实例化一个Channel对象。
此处只是初始化一个ServerBootStrap对象的channelFactory属性。设置channelFactory为ReflectiveChannelFactory(NioServerSocketChannel.class)。
二、bootstrap.bind时initAndRegister过程中new Channel
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
channel = channelFactory.newChannel();
init(channel);
.......
channelFactory.newChannel();
这句会调用ReflectiveChannelFactory的newChannel方法,调用NioServerSocketChannel的构造方法构造一个Channel。
NioServerSocketChannel
NioServerSocketChannel类后面单独讲
DEFAULT_SELECTOR_PROVIDER
NioServerSocketChannel.java
private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();
SelectorProvider.java
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;
provider = sun.nio.ch.DefaultSelectorProvider.create();
return provider;
}
});
}
}
provider中,如果SelectorProvider的provider有了就返回。
如果没有,则从系统配置中找配置的provider,如果有就实例化并返回。
System.getProperty("java.nio.channels.spi.SelectorProvider");
如果系统配置没有,则通过SPI加载配置的provider。使用了JDK的SPI能力,关键源码如下:
ServiceLoader<SelectorProvider> sl =
ServiceLoader.load(SelectorProvider.class,
ClassLoader.getSystemClassLoader());
如果SPI也没有配置provider,这通过jdk中DefaultSelectorProvider静态方法create()来创建provider。核心代码入下,根据运行操作系统,如果是linux则new一个EPollSelectorProvider。
public static SelectorProvider create() {
String osname = (String)AccessController.doPrivileged(new GetPropertyAction("os.name"));
if (osname.equals("SunOS")) {
return createProvider("sun.nio.ch.DevPollSelectorProvider");
} else {
return (SelectorProvider)(osname.equals("Linux") ? createProvider("sun.nio.ch.EPollSelectorProvider") : new PollSelectorProvider());
}
}
EPollSelectorProvider
类关系如下
EPollSelectorProvider和PollSelectorProvider继承SelectorProviderImpl这个抽象类,实现openSelector和inheritedChannel两个方法。
区别是EPollSelectorProvider的openSelector,返回EPollSelectorImpl对象
而PollSelectorProvider返回PollSelectorImpl对象。
这两个的区别后面单独说。
NioServerSocketChannel构造方法
public NioServerSocketChannel() {
this(newSocket(DEFAULT_SELECTOR_PROVIDER));
}
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>.
*/
//参考下文provider.openServerSocketChannel()讲解;
return provider.openServerSocketChannel();
} catch (IOException e) {
throw new ChannelException(
"Failed to open a server socket.", e);
}
}
public NioServerSocketChannel(ServerSocketChannel channel) {
//参考:AbstractNioChannel的构造方法章节
super(null, channel, SelectionKey.OP_ACCEPT);
config = new NioServerSocketChannelConfig(this, javaChannel().socket());
}
provider.openServerSocketChannel()
EPollSelectorImpl的openServerSocketChannel,看名字就能猜到,返回一个ServerSocketChannel。当然EPollSelectorImpl作为一个SelectorProvider也能获取UDP等。
public ServerSocketChannel openServerSocketChannel() throws IOException {
return new ServerSocketChannelImpl(this);
}
ServerSocketChannelImpl
ServerSocketChannelImpl(SelectorProvider sp) throws IOException {
super(sp);
this.fd = Net.serverSocket(true);
this.fdVal = IOUtil.fdVal(fd);
this.state = ST_INUSE;
}
Net.java
static FileDescriptor serverSocket(boolean stream) {
return IOUtil.newFD(socket0(isIPv6Available(), stream, true));
}
// Due to oddities SO_REUSEADDR on windows reuse is ignored
private static native int socket0(boolean preferIPv6, boolean stream, boolean reuse);
可见ServerSocketChannelImpl构造方法中,Net.serverSocket(true);
会调用native的方法,最终会进行socket函数的系统调用。并返回操作系统上的该socket的fd号,并将fd号封装在Java中的FileDescriptor对象中。
AbstractNioChannel的构造方法
protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
super(parent);
this.ch = ch;
this.readInterestOp = readInterestOp;
try {
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);
}
}
配置channel感兴趣的事件,并切设置channel的模式为非阻塞模式。