在上一篇中解析了NioEventLoopGroup,其中构造器中需要SelectorProvider,所以本篇就解析SelectorProvider。

解析

SelectorProvider

SelectorProvider就是为了创建DatagramChannel,Pipe,Selector,ServerSocketChannel,SocketChannel,System.inheritedChannel()而服务的,在相应的通道和选择器的open方法中调用系统默认的SelectorProvider相关的open*方法,创建相应的通道和选择器。SelectorProvider的provider方法主要是实例化SelectorProvider。

默认通过sun.nio.ch.DefaultSelectorProvider.create()创建,DefaultSelectorProvider屏蔽了不同的操作系统的不同实现方式。

继承关系

SelectorProvider是个抽象类。

1
public abstract class SelectorProvider {}

成员变量

1
2
private static final Object lock = new Object();
private static SelectorProvider provider = null;

核心方法

从系统配置中获取loadProviderFromProperty()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private static boolean loadProviderFromProperty() {
// 从环境变量中获取类名
String cn = System.getProperty("java.nio.channels.spi.SelectorProvider");
if (cn == null)
return false;
try {
// 反射生成对象
Class<?> c = Class.forName(cn, true,
ClassLoader.getSystemClassLoader());
provider = (SelectorProvider)c.newInstance();
return 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);
}
}
spi获取loadProviderAsService()

ServiceLoader是jdk实现的spi扩展,有两种配置的方式

  1. 直接通过类加载器加载类;
  2. 通过类加载器获取【META-INF/services/】目录下与类名一致的配置文件,文件中每行可以配置全限定类名,然后通过类名反射生成对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private static boolean loadProviderAsService() {

ServiceLoader<SelectorProvider> sl =
ServiceLoader.load(SelectorProvider.class,
ClassLoader.getSystemClassLoader());
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;
}
}
}
统一获取方法provider()

依次获取,如果获取到就返回:

  1. 当前已经有啦;
  2. 通过环境变量配置的;
  3. 通过jdk的spi获取的;
  4. 默认通过sun.nio.ch.DefaultSelectorProvider.create()生成。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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;
}
});
}
}

抽象方法

1
2
3
4
5
6
7
8
9
10
11
12
public abstract DatagramChannel openDatagramChannel()
throws IOException;
public abstract DatagramChannel openDatagramChannel(ProtocolFamily family)
throws IOException;
public abstract Pipe openPipe()
throws IOException;
public abstract AbstractSelector openSelector()
throws IOException;
public abstract ServerSocketChannel openServerSocketChannel()
throws IOException;
public abstract SocketChannel openSocketChannel()
throws IOException;

`