調用鏈完整還原
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 實現類
| 協議 | Handler 類全限定名 | 返回連接類型 |
| http | sun.net.www.protocol.http.Handler | HttpURLConnection |
| https | sun.net.www.protocol.https.Handler | HttpsURLConnection |
| ftp | sun.net.www.protocol.ftp.Handler | FtpURLConnection |
| jar | sun.net.www.protocol.jar.Handler | JarURLConnection |
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。
- 上一篇文章: Java Web request.getParameter 空指針異常:參數缺失導致 getBytes 拋 NPE 的排查與防御編程
- 下一篇文章: Android 計算直角三角形角度:Math.atan2 避免除零與象限判斷
Copyright ©
程式碼之家 All Rights Reserved