天天看點

java nio SelectorProvider源碼分析簡介字段lock,provider,構造函數,方法loadProviderFromProperty,loadProviderAsService,provider 方法2個openDatagramChannel,openPipe/Selector/ServerSocketChannel/SocketChannel,inheritedChannel

目錄

簡介

字段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 
           
java nio SelectorProvider源碼分析簡介字段lock,provider,構造函數,方法loadProviderFromProperty,loadProviderAsService,provider 方法2個openDatagramChannel,openPipe/Selector/ServerSocketChannel/SocketChannel,inheritedChannel

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

繼續閱讀