首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

Java URL.openConnection() 源碼追蹤:Handler 工廠機制與協議特定實現類加載全過程

     編輯:程式設計疑難解答

調用鏈完整還原

URL url = new URL("https://www.sina.com.cn");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();

核心類與關鍵步驟

1. URL 構造器解析協議並獲取 Handler

// java.net.URL
public URL(String spec) throws MalformedURLException {
    // 解析出 protocol = "http"
    // 若未指定 handler,調用 getURLStreamHandler(protocol)
}

2. getURLStreamHandler 兩級查找


// 級別 1:系統屬性 java.protocol.handler.pkgs 指定的包前綴
// 級別 2:內置工廠 sun.net.www.protocol.Factory
private static URLStreamHandler getURLStreamHandler(String protocol) {
    // 1. 系統屬性包前綴查找
    String pkgPrefix = System.getProperty("java.protocol.handler.pkgs", "");
    if (!pkgPrefix.isEmpty()) {
        try {
            Class clazz = Class.forName(pkgPrefix + "." + protocol + ".Handler");
            return (URLStreamHandler) clazz.newInstance();
        } catch (Exception ignored) {}
    }
    // 2. 內置工廠查找
    return Factory.getDefaultFactory().createURLStreamHandler(protocol);
}

3. 內置工廠實現(關鍵)


// sun.net.www.protocol.Factory
private static class Factory implements URLStreamHandlerFactory {
    private static final String PREFIX = "sun.net.www.protocol";
    
    public URLStreamHandler createURLStreamHandler(String protocol) {
        String className = PREFIX + "." + protocol + ".Handler"; // 如 "sun.net.www.protocol.http.Handler"
        try {
            Class clazz = Class.forName(className);
            return (URLStreamHandler) clazz.newInstance();
        } catch (Exception e) {
            throw new InternalError("could not load " + protocol + " handler");
        }
    }
}

4. 具體協議 Handler 實現類

5. openConnection 最终調用


// java.net.URL
public URLConnection openConnection() throws IOException {
    return handler.openConnection(this);  // 委托給具體 Handler
}

// sun.net.www.protocol.http.Handler
protected URLConnection openConnection(URL u) throws IOException {
    return new HttpURLConnection(u);  // 創建 HTTP 專用連接
}

關鍵設計模式:工廠模式 + SPI (Service Provider Interface)

  • 解耦:URL 不依賴具體協議實現,只依賴抽象 URLStreamHandler。
  • 可擴展:自定義協議只需實現 URLStreamHandler 並配置 java.protocol.handler.pkgs 系統屬性,無需修改 JDK 源碼。
  • 延遲加載:首次使用某協議時才加載對應 Handler 類。

調試技巧:查看實際加載的 Handler

URL url = new URL("https://example.com");
System.out.println(url.getURLStreamHandler("http").getClass().getName());
// 輸出:sun.net.www.protocol.http.Handler

總結

url.openConnection() 通過 協議字符串 → 系統屬性前綴查找 → 內置工廠類名拼裝 → 反射實例化 Handler → 委托創建連接 的鏈路,實現了協議處理的標準化與可擴展性。HTTP 場景下,最終實現類為 sun.net.www.protocol.http.Handler,返回 HttpURLConnection。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
協議Handler 類全限定名返回連接類型
httpsun.net.www.protocol.http.HandlerHttpURLConnection
httpssun.net.www.protocol.https.HandlerHttpsURLConnection
ftpsun.net.www.protocol.ftp.HandlerFtpURLConnection
jarsun.net.www.protocol.jar.HandlerJarURLConnection