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 方法,在不一樣的平臺有不一樣的實現。
天天用心記錄一點點。內容也許不重要,但習慣很重要!