Netty是Java中最流行的一个高性能的通讯框架,被广泛应用于各个生产应用框架中,如Hadoop、Spark、Zookeeper等。Netty4.0之后的版本主要是基于JDK的NIO实现通讯,同时又绕过了JDK自带NIO的许多BUG。众所周知,JDK实现了跨平台功能,同时基于NIO实现的Netty也实现了跨平台的特性,但Netty是如何实现这个功能特性的呢?下面通过解读源码的方式进行讲解。
前提
本文讲述的Netty版本为4.1.39.Final,可在Maven工程中添加如下依赖:
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.39.Final</version>
</dependency>
源码讲解
1、NioEventLoopGroup构造方法
/**
* Create a new instance using the default number of threads, the default {@link ThreadFactory} and
* the {@link SelectorProvider} which is returned by {@link SelectorProvider#provider()}.
*/
public NioEventLoopGroup() {
this(0);
}
/**
* Create a new instance using the specified number of threads, {@link ThreadFactory} and the
* {@link SelectorProvider} which is returned by {@link SelectorProvider#provider()}.
*/
public NioEventLoopGroup(int nThreads) {
this(nThreads, (Executor) null);
}
/**
* Create a new instance using the specified number of threads, the given {@link ThreadFactory} and the
* {@link SelectorProvider} which is returned by {@link SelectorProvider#provider()}.
*/
public NioEventLoopGroup(int nThreads, ThreadFactory threadFactory) {
this(nThreads, threadFactory, SelectorProvider.provider());
}
//所有的构造方法都会最终调用NioEventLoopGroup(int nThreads, Executor executor)
public NioEventLoopGroup(int nThreads, Executor executor) {
this(nThreads, executor, SelectorProvider.provider());
}
查阅NioEventLoopGroup构造方法,所有的构造方法最终都会调用NioEventLoopGroup(int nThreads, Executor executor),该构造方法中自动传入了一个参数SelectorProvider.provider()
2、SelectorProvider.provider()方法
public static SelectorProvider provider() {
synchronized (lock) {
if (provider != null)
return provider;
return AccessController.doPrivileged(
new PrivilegedAction<SelectorProvider>() {
public SelectorProvider run() {
if (loadProviderFromProperty()) //调用了loadProviderFromProperty()方法
return provider;
if (loadProviderAsService()) //调用了loadProviderAsService()方法
return provider;
provider = sun.nio.ch.DefaultSelectorProvider.create();
return provider;
}
});
}
}
根据上述代码中,provider为成员变量,在首次初始化NioEventLoopGroup时,provider为null。后续分别调用了loadProviderFromProperty()和loadProviderAsService()两个方法,下面分别查看两个方法:
private static boolean loadProviderFromProperty() {
String cn = System.getProperty("java.nio.channels.spi.SelectorProvider"); //取系统参数
if (cn == null)
return false; //参数如果为空,则返回false
try {
Class<?> c = Class.forName(cn, true,
ClassLoader.getSystemClassLoader());
provider = (SelectorProvider)c.newInstance(); //通过反射实例化一个SelectorProvider
return true; //实例化成功后返回true
} catch (ClassNotFoundException x) {
throw new ServiceConfigurationError(null, x);
} catch (IllegalAccessException x) {
throw new ServiceConfigurationError(null, x);
} catch (InstantiationException x) {
throw new ServiceConfigurationError(null, x);
} catch (SecurityException x) {
throw new ServiceConfigurationError(null, x);
}
}
loadProviderFromProperty()方法中取系统的property参数,在系统默认的情况下,java.nio.channels.spi.SelectorProvider是为空的,因此会返回false。
private static boolean loadProviderAsService() {
ServiceLoader<SelectorProvider> sl =
ServiceLoader.load(SelectorProvider.class,
ClassLoader.getSystemClassLoader()); //通过JDK自带的ServiceLoader方式进行实例化
Iterator<SelectorProvider> i = sl.iterator();
for (;;) {
try {
if (!i.hasNext())
return false;
provider = i.next();
return true;
} catch (ServiceConfigurationError sce) {
if (sce.getCause() instanceof SecurityException) {
// Ignore the security exception, try the next provider
continue;
}
throw sce;
}
}
}
loadProviderAsService()方法通过JDK自带的ServiceLoader方法进行实例化,由于SelectorProvider为一个抽象类,并非接口,因此iterator为空,该方法返回false。
3、DefaultSelectorProvider
SelectorProvider.provider()最终会走到sun.nio.ch.DefaultSelectorProvider.create(),查看create()方法,发现该处为Netty的精明之处,调用了JDK自带的DefaultSelectorProvider类,该类会根据不同平台实例化不同的类:
- mac平台
public class DefaultSelectorProvider {
private DefaultSelectorProvider() {
}
public static SelectorProvider create() {
return new KQueueSelectorProvider(); //mac平台下返回的实例
}
}
- windows平台
public class DefaultSelectorProvider {
private DefaultSelectorProvider() {
}
public static SelectorProvider create() {
return new WindowsSelectorProvider();//windows返回的实例
}
}