目录
字段lock,provider,构造函数,方法loadProviderFromProperty,loadProviderAsService,provider
方法2个openDatagramChannel,openPipe/Selector/ServerSocketChannel/SocketChannel,inheritedChannel
简介
package java.nio.channels.spi;
import java.io.IOException;
import java.net.ProtocolFamily;
import java.nio.channels.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Iterator;
import java.util.ServiceLoader;
import java.util.ServiceConfigurationError;
import sun.security.action.GetPropertyAction;
/**
* 用于选择器和可选择通道的服务提供程序类。
*
* <p> 选择器提供程序是这个类的一个具体子类,它有无参构造函数,并实现下面指定的抽象方法。
* Java虚拟机的给定调用,维护一个单系统范围的默认提供程序实例,该实例由provider方法返回。
* 该方法的第一次调用将定位默认提供程序,如下所示。
*
* <p> 系统默认提供程序由DatagramChannel、Pipe、Selector、ServerSocketChannel和SocketChannel类的静态open方法使用。
* 它也被System.inheritedChannel()方法使用。
* 程序可以使用默认提供程序之外的提供程序,通过实例化该提供程序,然后直接调用该类中定义的open方法。
*
* <p> 这个类中的所有方法对于多个并发线程使用都是安全的。
*
*
* @author Mark Reinhold
* @author JSR-51 Expert Group
* @since 1.4
*/
public abstract class SelectorProvider
字段lock,provider,构造函数,方法loadProviderFromProperty,loadProviderAsService,provider
private static final Object lock = new Object();
// 内部保存一个静态的provider
private static SelectorProvider provider = null;
/**
* 初始化这个类的实例
*
* @throws SecurityException
* If a security manager has been installed and it denies
* {@link RuntimePermission}<tt>("selectorProvider")</tt>
*/
protected SelectorProvider() {
// 检查能否使用selectorProvider
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkPermission(new RuntimePermission("selectorProvider"));
}
private static boolean loadProviderFromProperty() {
String cn = System.getProperty("java.nio.channels.spi.SelectorProvider");
if (cn == null)
return false;
try {
// 调用系统加载器,调用它的无参构造器,赋值给provider
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);
}
}
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;
}
}
}
/**
* 返回此Java虚拟机调用的系统范围默认选择器提供程序。
*
* <p> 这个方法的第一次调用,定位了默认的provider对象,如下所示:</p>
*
* <ol>
*
* <li><p> 如果系统属性为java.nio.channels.spi.SelectorProvider被定义,然后它被当作一个具体提供程序类的完全限定名。
* 类被加载并实例化;
* 如果此过程失败,则抛出一个未指定的错误。</p></li>
*
* <li><p> 如果提供程序类已安装在系统类加载器可见的jar文件中,并且该jar文件包含一个名为java.nio.channels.spi.SelectorProvider的提供程序配置文件,
* 在资源目录 META-INF/services,然后获取该文件中指定的第一个类名称。
* 类被加载并实例化;
* 如果此过程失败,则抛出一个未指定的错误。</p></li>
*
* <li><p> 最后,如果上述任何一个都没有指定提供程序,则实例化系统默认的提供程序类并返回结果。</p></li>
*
* </ol>
*
* <p> 此方法的后续调用将返回第一次调用所返回的提供者。 </p>
*
* @return The system-wide default selector provider
*/
public static SelectorProvider provider() {
synchronized (lock) {
if (provider != null)
return provider;
return AccessController.doPrivileged(
new PrivilegedAction<SelectorProvider>() {
public SelectorProvider run() {
// 先从系统属性获得,再从service获得,最后返回默认provider
if (loadProviderFromProperty())
return provider;
if (loadProviderAsService())
return provider;
provider = sun.nio.ch.DefaultSelectorProvider.create();
return provider;
}
});
}
}
方法2个openDatagramChannel,openPipe/Selector/ServerSocketChannel/SocketChannel,inheritedChannel
/**
* 打开数据报通道。
*
* @return The new channel
*
* @throws IOException
* If an I/O error occurs
*/
public abstract DatagramChannel openDatagramChannel()
throws IOException;
/**
* 打开数据报通道。
*
* @param family
* The protocol family
*
* @return A new datagram channel
*
* @throws UnsupportedOperationException
* If the specified protocol family is not supported
* @throws IOException
* If an I/O error occurs
*
* @since 1.7
*/
public abstract DatagramChannel openDatagramChannel(ProtocolFamily family)
throws IOException;
/**
* 打开管道。
*
* @return The new pipe
*
* @throws IOException
* If an I/O error occurs
*/
public abstract Pipe openPipe()
throws IOException;
/**
* 打开一个选择器
*
* @return The new selector
*
* @throws IOException
* If an I/O error occurs
*/
public abstract AbstractSelector openSelector()
throws IOException;
/**
* 打开一个服务器-套接字通道。
*
* @return The new channel
*
* @throws IOException
* If an I/O error occurs
*/
public abstract ServerSocketChannel openServerSocketChannel()
throws IOException;
/**
* 打开套接字通道。
*
* @return The new channel
*
* @throws IOException
* If an I/O error occurs
*/
public abstract SocketChannel openSocketChannel()
throws IOException;
/**
* 返回从创建此java虚拟机的实体继承的通道。
*
* <p> 在许多操作系统上,进程(如Java虚拟机)的启动方式允许进程从创建该进程的实体继承一个通道。
* 这样做的方式是依赖于系统的,因为是可能的实体,该通道可能被连接。
* 例如,在UNIX系统上,Internet服务守护进程(inetd)用于启动程序,在请求到达关联的网络端口时为请求提供服务。
* 在本例中,启动的进程继承表示网络套接字的通道。
*
* <p> 在继承的通道代表一个网络套接字的情况下,
* 然后通道类型由方法返回,如下:
*
* <ul>
*
* <li><p> 如果继承的通道表示面向流的连接套接字,则返回SocketChannel。
* 套接字通道(至少在开始时)在阻塞模式下绑定到套接字地址,并连接到对等点。
* </p></li>
*
* <li><p> 如果继承的通道表示面向流侦听套接字,则返回ServerSocketChannel。
* 服务器-套接字通道(至少在开始时)处于阻塞模式,并绑定到套接字地址。
* </p></li>
*
* <li><p> 如果继承的通道是面向数据的套接字,那么返回一个DatagramChannel。
* 数据报通道至少在初始阶段处于阻塞模式,并绑定到一个套接字地址。
* </p></li>
*
* </ul>
*
* <p> 除了所描述的面向网络的通道之外,这种方法将来还可能返回其他类型的通道。
*
* <p> 该方法的第一次调用将创建返回的通道。该方法的后续调用将返回相同的通道。</p>
*
* @return The inherited channel, if any, otherwise <tt>null</tt>.
*
* @throws IOException
* If an I/O error occurs
*
* @throws SecurityException
* If a security manager has been installed and it denies
* {@link RuntimePermission}<tt>("inheritedChannel")</tt>
*
* @since 1.5
*/
public Channel inheritedChannel() throws IOException {
return null;
}