咱們先捋一遍再看源碼:
Selector selector = Selector.open(); 在默認情況下生成了一個WindowsSelectorImpl實例,並且建立了Pipe
創建Selector對象:
Selector selector = Selector.open();
Selector實現原理:
SocketChannel、ServerSocketChannel和Selector的實例初始化都通過SelectorProvider類實現,我們先獲取相應的SelectorProvider。
public static SelectorProvider provider() {
synchronized (lock) {
//provider不爲空,直接返回provider
if (provider != null)
return provider;
return AccessController.doPrivileged(
new PrivilegedAction<SelectorProvider>() {
public SelectorProvider run() {
//由JDK的參數-Djava.nio.channels.spi.SelectorProvider=class設置的class來反射構造SelectorProvider
if (loadProviderFromProperty())
return provider;
//從jar中的目錄META-INF/services配置文件中找參數java.nio.channels.spi.SelectorProvider=class設置的第一個class來反射構造SelectorProvider
if (loadProviderAsService())
return provider;
provider = sun.nio.ch.DefaultSelectorProvider.create();
return provider;
}
});
}
}
AccessController.doPrivileged屬於特權操作,意思是不管這個方法由哪個用戶發起,都無需對此操作涉及的資源(文件讀寫特權等等)進行檢查。
由於SelectorProvider在不同操作系統下有不同的實現。
provider = sun.nio.ch.DefaultSelectorProvider.create();根據不同操作系統返回不同實現類,這裏主要以Windows實現梳理整個流程,windows平臺就返回WindowsSelectorProvider。
package sun.nio.ch;
import java.io.IOException;
import java.nio.channels.spi.AbstractSelector;
public class WindowsSelectorProvider extends SelectorProviderImpl {
public WindowsSelectorProvider() {
}
public AbstractSelector openSelector() throws IOException {
return new WindowsSelectorImpl(this);
}
}
以默認情況爲例,採用的就是WindowsSelectorImpl.
在Windows操作系統JDK裏sun.nio.ch.DefaultSelectorProvider源代碼:
package sun.nio.ch;
import java.nio.channels.spi.SelectorProvider;
public class DefaultSelectorProvider
{
public static SelectorProvider create()
{
return new WindowsSelectorProvider();
}
}
這裏直接返回WindowsSelectorProvider,即就是沒進行任何的配置,則會使用WindowsSelectorProvider,其構造方法爲空,沒有任何實現,獲得SelectorProvider後,調用openSelector()方法獲得對應Selector。
private final Pipe wakeupPipe = Pipe.open();
WindowsSelectorImpl(SelectorProvider var1) throws IOException {
super(var1);
this.wakeupSourceFd = ((SelChImpl)this.wakeupPipe.source()).getFDVal();
SinkChannelImpl var2 = (SinkChannelImpl)this.wakeupPipe.sink();
var2.sc.socket().setTcpNoDelay(true);
this.wakeupSinkFd = var2.getFDVal();
this.pollWrapper.addWakeupSocket(this.wakeupSourceFd, 0);
}
觀察構造方法,首先需要用到wakeupPipe, 這個成員的取得需要Pipe調用open()方法。
public static Pipe open() throws IOException {
return SelectorProvider.provider().openPipe();
}
直接調用了SelectorProvider的openPipe()方法:
public Pipe openPipe() throws IOException {
return new PipeImpl(this);
}
openPipe()方法在WindowsSelectorProvider的父類SelectorProviderImpl類中實現,
openPipe()的實現調用了pipeImpl的構造方法,
static {
Util.load();
byte[] var0 = new byte[8];
boolean var1 = IOUtil.randomBytes(var0);
if(var1) {
rnd = new Random(ByteBuffer.wrap(var0).getLong());
} else {
rnd = new Random();
}
}
PipeImpl(SelectorProvider var1) throws IOException {
try {
AccessController.doPrivileged(new PipeImpl.Initializer(var1));
} catch (PrivilegedActionException var3) {
throw (IOException)var3.getCause();
}
}
這裏首先在PipeImpl的靜態塊中會產生一個隨機數保存,然後在其構造方法中,通過AccessController調用doPrivileged方法new一個PipeImpl中內部類Initializer,這個方法會調用傳入的類所實現的run()方法,並保證其內部所涉及的權限問題,接下來看其run()方法:
public Void run() throws IOException {
PipeImpl.Initializer.LoopbackConnector var1 = new PipeImpl.Initializer.LoopbackConnector();
var1.run();
if(this.ioe instanceof ClosedByInterruptException) {
this.ioe = null;
Thread var2 = new Thread(var1) {
public void interrupt() {
}
};
var2.start();
while(true) {
try {
var2.join();
break;
} catch (InterruptedException var4) {
;
}
}
Thread.currentThread().interrupt();
}
if(this.ioe != null) {
throw new IOException("Unable to establish loopback connection", this.ioe);
} else {
return null;
}
}
該方法內部會初始化Pipe管道的讀寫對象,初始化完成後對異常進行分類處理。啓動了一個線程,看LoopbackConnector(),內部類Initializer的內部類LoopbackConnector,通過LoopbackConnector的實例化對象調用其run()方法:
private LoopbackConnector() {
}
public void run() {
//定義服務端Channel
ServerSocketChannel var1 = null;
//定義兩個客戶端通道分別負責讀寫
SocketChannel var2 = null;
SocketChannel var3 = null;
try {
//初始化兩個ByteBuffer緩衝區,支持讀寫操作
ByteBuffer var4 = ByteBuffer.allocate(16);
ByteBuffer var5 = ByteBuffer.allocate(16);
InetAddress var6 = InetAddress.getByName("127.0.0.1");
assert var6.isLoopbackAddress();
//對服務端創建的IP和端口進行存儲,
InetSocketAddress var7 = null;
//自旋處理,直接成功初始化出讀寫對象
while(true) {
// 初始化ServerSocketChannel,用戶提供服務
if (var1 == null || !var1.isOpen()) {
var1 = ServerSocketChannel.open();
var1.socket().bind(new InetSocketAddress(var6, 0));
var7 = new InetSocketAddress(var6, var1.socket().getLocalPort());
}
//通過已經初始化的IP和端口打開一個寫通道
var2 = SocketChannel.open(var7);
PipeImpl.RANDOM_NUMBER_GENERATOR.nextBytes(var4.array());
do {
//將數據全部寫出去
var2.write(var4);
} while(var4.hasRemaining());
var4.rewind();
// 通過服務端獲取一個讀請求
// 此處讀取上一步寫的數據
var3 = var1.accept();
do {
// 讀取到寫數據, 添加到另一個緩衝區
var3.read(var5);
} while(var5.hasRemaining());
var5.rewind();
// 如果讀寫數據一致,說明管道通信正常,初始化管道的讀對象和寫對象
if (var5.equals(var4)) {
// 讀對象
PipeImpl.this.source = new SourceChannelImpl(Initializer.this.sp, var2);
// 寫對象
PipeImpl.this.sink = new SinkChannelImpl(Initializer.this.sp, var3);
break;
}
var3.close();
var2.close();
}
} catch (IOException var18) {
try {
if (var2 != null) {
var2.close();
}
if (var3 != null) {
var3.close();
}
} catch (IOException var17) {
;
}
Initializer.this.ioe = var18;
} finally {
try {
if (var1 != null) {
var1.close();
}
} catch (IOException var16) {
;
}
}
}
val1通過ServerSocketChannel.open(),通過SelectorProviderImpl的openServerSocketChannel()
public ServerSocketChannel openServerSocketChannel() throws IOException {
return new ServerSocketChannelImpl(this);
}
返回ServerSocketChannelImpl
ServerSocketChannelImpl(SelectorProvider var1) throws IOException {
super(var1);
this.fd = Net.serverSocket(true);
this.fdVal = IOUtil.fdVal(this.fd);
this.state = 0;
}
回到WindowsSelectorImpl的構造方法,用wakeupSourceFd保存source(SourceChannelImpl)的fdVal值,用wakeupSinkFd保存sink(SinkChannelImpl)的fdVal值;禁用Nagle算法,最後使用pollWrpper成員保存source的fdVal值。得到source的fd跟sink的fd並保存,把wakeupSourceFd加到PoolWrapper中。至此selector創建完畢。
WindowsSelectorImpl(SelectorProvider var1) throws IOException {
super(var1);
this.wakeupSourceFd = ((SelChImpl)this.wakeupPipe.source()).getFDVal();
SinkChannelImpl var2 = (SinkChannelImpl)this.wakeupPipe.sink();
var2.sc.socket().setTcpNoDelay(true);
this.wakeupSinkFd = var2.getFDVal();
this.pollWrapper.addWakeupSocket(this.wakeupSourceFd, 0);
}
void addWakeupSocket(int var1, int var2) {
this.putDescriptor(var2, var1);
this.putEventOps(var2, Net.POLLIN);
}
void putDescriptor(int var1, int var2) {
this.pollArray.putInt(SIZE_POLLFD * var1 + 0, var2);
}
void putEventOps(int var1, int var2) {
this.pollArray.putShort(SIZE_POLLFD * var1 + 4, (short)var2);
}