NIO源码阅读笔记(一) Selector启动分析

Selector通过调用Selector.open()方法启动的:

	public static Selector open() throws IOException {
        return SelectorProvider.provider().openSelector();
    }

SelectorProvider.provider()方法如下,返回值为SelectorProvider:

private static final Object lock = new Object();
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() {
                            if (loadProviderFromProperty())
                                return provider;
                            if (loadProviderAsService())
                                return provider;
                            provider = sun.nio.ch.DefaultSelectorProvider.create();
                            return provider;
                        }
                    });
        }
    }

首先判断provider是否为null,如果不为null则直接返回当前已经存在的provider;
如果provider为null,可以看到在run()方法中一共有三种生成provider的方法。
第一个if调用了loadProviderFromProperty()方法:

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);
        }
    }

先通过System.getProperty(“java.nio.channels.spi.SelectorProvider”)获取键值为java.nio.channels.spi.SelectorProvider的系统属性,如果没有设置该系统属性,则返回false;否则通过类加载器获取其实现类,并通过反射机制获取其实例化对象为provider 赋值,并返回true。

第二个if调用了loadProviderAsService()方法:

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;
            }
        }
    }

通过ServiceLoader的load方法加载"META-INF/services/"路径下指明的SelectorProvider.class的实现类,如果设置有相应的文件则成功赋值并返回true,否则返回false。
如果以上两步判断都为false,则使用默认的SelectorProvider,即调用sun.nio.ch.DefaultSelectorProvider.create():

	public static SelectorProvider create() {
        return new WindowsSelectorProvider();
    }
	public WindowsSelectorProvider() {
    }

直接返回WindowsSelectorProvider作为provider的值。
run方法运行结束后,SelectorProvider一定会有值。
接下来看SelectorProvider的openSelector方法:

	public abstract AbstractSelector openSelector()
        throws IOException;

这是一个抽象方法,真正的实现是在WindowsSelectorProvider中:

	public AbstractSelector openSelector() throws IOException {
        return new WindowsSelectorImpl(this);
    }
	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);
    }

WindowsSelectorImpl的构造方法中先调用了父类SelectorImpl的构造方法:

 	protected Set<SelectionKey> selectedKeys = new HashSet();
    protected HashSet<SelectionKey> keys = new HashSet();
    private Set<SelectionKey> publicKeys;
    private Set<SelectionKey> publicSelectedKeys;
	protected SelectorImpl(SelectorProvider var1) {
        super(var1);
        if (Util.atBugLevel("1.4")) {
            this.publicKeys = this.keys;
            this.publicSelectedKeys = this.selectedKeys;
        } else {
            this.publicKeys = Collections.unmodifiableSet(this.keys);
            this.publicSelectedKeys = Util.ungrowableSet(this.selectedKeys);
        }

    }

SelectorImpl同样调用了其父类AbstractSelector的构造方法:

	 private final SelectorProvider provider;
	protected AbstractSelector(SelectorProvider provider) {
        this.provider = provider;
    }

在AbstractSelector的构造方法中完成了对provider的赋值。
回到WindowsSelectorImpl的构造方法,有成员如下:

	private final Pipe wakeupPipe = Pipe.open();
	 public static Pipe open() throws IOException {
        return SelectorProvider.provider().openPipe();
    }

其中SelectorProvider.provider()在上边已经分析过了,openPipe的具体实现在SelectorProviderImpl中:

	public Pipe openPipe() throws IOException {
        return new PipeImpl(this);`在这里插入代码片`
    }

调用了PipeImpl的构造方法,传入了当前的SelectorProvider。

	PipeImpl(SelectorProvider var1) throws IOException {
        try {
            AccessController.doPrivileged(new PipeImpl.Initializer(var1));
        } catch (PrivilegedActionException var3) {
            throw (IOException)var3.getCause();
        }
    }

该构造方法传入了SelectorProvider到PipeImpl的内部类Initializer并运行其run方法(private class Initializer implements PrivilegedExceptionAction):

		private final SelectorProvider sp;
        private IOException ioe;

        private Initializer(SelectorProvider var2) {
            this.ioe = null;
            this.sp = var2;
        }

该构造方法令ioe为null,并将sp赋值为SelectorProvider。

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;
            }
      }

在run方法中先产生LoopbackConnector对象,LoopbackConnector是Initializer的内部类,然后再通过LoopbackConnector的实例化对象调用其run方法:

			private LoopbackConnector() {
            }

            public void run() {
                ServerSocketChannel var1 = null;
                SocketChannel var2 = null;
                SocketChannel var3 = null;

                try {
                    ByteBuffer var4 = ByteBuffer.allocate(16);
                    ByteBuffer var5 = ByteBuffer.allocate(16);
                    InetAddress var6 = InetAddress.getByName("127.0.0.1");

                    assert var6.isLoopbackAddress();

                    InetSocketAddress var7 = null;

                    while(true) {
                        if (var1 == null || !var1.isOpen()) {
                            var1 = ServerSocketChannel.open();
                            var1.socket().bind(new InetSocketAddress(var6, 0));
                            var7 = new InetSocketAddress(var6, var1.socket().getLocalPort());
                        }

                        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) {
                        ;
                    }

                }

            }

定义了一个ServerSocketChannel var1两个SocketChannel var2和var3以及两个ByteBuffer var4和var5;生成了一个InetAddress var6。
在while循环中检查ServerSocketChannel是否为null或者未打开,如果未true则打开ServerSocketChannel并为其绑定地址var6和端口号0,令var7的地址是var6的地址,端口号为ServerSocketChannel的端口号;通过var7将SocketChannel var2与ServerSocketChannel var1建立连接,生成随机数通过SocketChannel var2发送给ServerSocketChannel var1。接着ServerSocketChannel调用accept方法侦听刚才的连接产生一个SocketChannel对象var3,从var3中读取数据存放在缓冲区var5中。比较var4和var5,如果一致则给PipeImpl的成员source和sink分别初始化保存起来,若不一致就继续循环,直至一致。如果出现IO异常则将异常保存在ioe中,关闭所有channel,循环结束。
回到Initializer的run方法,如果ioe中保存的异常是ClosedByInterruptException则需要开启一个新的线程重新运行LoopbackConnector的run方法,并调用join方法保证运行顺序。如果ioe不为null,则抛出异常。
回到WindowsSelectorImpl的构造方法,用wakeupSourceFd保存source(SourceChannelImpl)的fdVal值,用wakeupSinkFd保存sink(SinkChannelImpl)的fdVal值;禁用Nagle算法,最后使用pollWrpper成员保存source的fdVal值。至此selector创建完毕。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值