NIO 源码分析(04) 从 SelectorProvider 看 JDK SPI 机制html
[toc]java
Netty 系列目录(https://www.cnblogs.com/binarylei/p/10117436.html)socket
SelectorProvider 定义了建立 Selector、ServerSocketChannel、SocketChannel 等方法,采用 JDK 的 Service Provider Interface (SPI) 方式实现。ide
public static ServerSocketChannel open() throws IOException { return SelectorProvider.provider().openServerSocketChannel(); }
1、SelectorProvider SPI
SelectorProvider 是一个抽象类,须要子类实现。主要方法以下:工具
public abstract DatagramChannel openDatagramChannel() throws IOException; public abstract DatagramChannel openDatagramChannel(ProtocolFamily family) throws IOException; public abstract ServerSocketChannel openServerSocketChannel() throws IOException; public abstract SocketChannel openSocketChannel() throws IOException; public abstract AbstractSelector openSelector() throws IOException; public abstract Pipe openPipe() throws IOException;
<b>总结:</b> SelectorProvider 至关于一个工厂类,提供了对 DatagramChannel、ServerSocketChannel、SocketChannel、Selector 了建立方法。源码分析
java.nio.channels.spi 中提供了一系列的抽象类,由具体的厂商实现,固然咱们通常使用的都是 JDK 本身的实现。相关的 SPI 接口以下:this
AbstractInterruptibleChannel -> SocketChannelImpl/ServerSocketChannelImpl AbstractSelectableChannel AbstractSelectionKey -> SelectionKeyImpl AbstractSelector -> WindowsSelectorImpl/PollSelectorImpl/EpollSelectorImpl SelectorProvider -> DefaultSelectorProvider
2、SelectorProvider 加载过程
2.1 SelectorProvider 加载
private static SelectorProvider provider = null; public static SelectorProvider provider() { synchronized (lock) { if (provider != null) return provider; return AccessController.doPrivileged( new PrivilegedAction<SelectorProvider>() { public SelectorProvider run() { // 1. java.nio.channels.spi.SelectorProvider 属性指定实现类 if (loadProviderFromProperty()) return provider; // 2. SPI 指定实现类 if (loadProviderAsService()) return provider; // 3. 默认实现,Windows 和 Linux 下不一样 provider = sun.nio.ch.DefaultSelectorProvider.create(); return provider; } }); } }
<b>总结:</b> SelectorProvider 提供了三种方式来自定义 SelectorProvider 的实现类。url
java.nio.channels.spi.SelectorProvider
属性指定实现类- 采用 SPI 方法建立 SelectorProvider
- 默认实现 DefaultSelectorProvider,Windows 和 Linux 下具体的实现不一样。
public abstract class SelectorProviderImpl extends SelectorProvider { public DatagramChannel openDatagramChannel() throws IOException { return new DatagramChannelImpl(this); } public DatagramChannel openDatagramChannel(ProtocolFamily family) throws IOException { return new DatagramChannelImpl(this, family); } public Pipe openPipe() throws IOException { return new PipeImpl(this); } public abstract AbstractSelector openSelector() throws IOException; public ServerSocketChannel openServerSocketChannel() throws IOException { return new ServerSocketChannelImpl(this); } public SocketChannel openSocketChannel() throws IOException { return new SocketChannelImpl(this); } }
<b>总结:</b> SelectorProviderImpl 提供了 ServerSocketChannel、SocketChanne 的建立,至于 Selector 在不一样的平台下有不一样的实现。spa
2.2 Windows 下 DefaultSelectorProvider
public class DefaultSelectorProvider { public static SelectorProvider create() { return new sun.nio.ch.WindowsSelectorProvider(); } } public class WindowsSelectorProvider extends SelectorProviderImpl { public AbstractSelector openSelector() throws IOException { return new WindowsSelectorImpl(this); } }
2.3 Unix 下 DefaultSelectorProvider
public class DefaultSelectorProvider { public static SelectorProvider create() { String osname = AccessController .doPrivileged(new GetPropertyAction("os.name")); if (osname.equals("SunOS")) return createProvider("sun.nio.ch.DevPollSelectorProvider"); if (osname.equals("Linux")) return createProvider("sun.nio.ch.EPollSelectorProvider"); return new sun.nio.ch.PollSelectorProvider(); } }
<b>总结:</b> Unix 平台下须要根据不一样的操做系统选择不一样的 Selector,例如 Linux 下是 EPollSelectorProvider。操作系统
public class EPollSelectorProvider extends SelectorProviderImpl { public AbstractSelector openSelector() throws IOException { return new EPollSelectorImpl(this); } public Channel inheritedChannel() throws IOException { return InheritedChannel.getChannel(); } }
<b>总结:</b> 不管是 WindowsSelectorProvider 仍是 EPollSelectorImpl,它们都继承 SelectorProviderImpl,关于 ServerSocketChannel、SocketChanne 的建立都是同样的,区别是 Selector 有兼容性问题。难道 Socket 在 Windows 和 Linux 下就没有区别吗,确定也是有兼容性问题的。
ServerSocketChannelImpl(SelectorProvider sp) throws IOException { super(sp); this.fd = Net.serverSocket(true); // 建立 socket,这个 Net 工具自己是跨平台的 this.fdVal = IOUtil.fdVal(fd); this.state = ST_INUSE; }
Socket 的建立是在 sun.nio.ch.Net 工具类的 socket0 完成的,这个类不少方法都是 native 方法,在不一样的平台有不一样的实现。
天天用心记录一点点。内容也许不重要,但习惯很重要!