許多 Java 開發者在學習 JDBC 時,都會被教導要寫這行代碼:Class.forName("com.mysql.cj.jdbc.Driver")。但為什麼需要這行代碼?它背後的原理是什麼?在現代 Java 版本中是否還需要?本文將從 JVM 類載入機制、JDBC SPI 規範、驅動註冊流程三個維度,徹底講透這個經典問題。
Class.forName() 的本質是觸發驅動類的「靜態初始化塊」,使其向 DriverManager 註冊自己。 只要達成「驅動類被載入並完成初始化」這一目標,任何方式皆可替代它。
// 最常見寫法
Class.forName("com.mysql.cj.jdbc.Driver");
// 或者顯式實例化 (效果相同)
new com.mysql.cj.jdbc.Driver();
Class.forName 會載入類並執行靜態初始化塊 (static { ... })。MySQL 驅動的靜態塊中包含註冊邏輯:
// mysql-connector-j 8.x 來源碼片段
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException e) {
throw new RuntimeException("Can't register driver!", e);
}
}
// ...
}
**從 JDK 6 (JDBC 4.0 規範) 開始,完全不需要手動呼叫 Class.forName。**
原理:驅動 JAR 包的 META-INF/services/java.sql.Driver 文件中聲明了實現類名稱。DriverManager 初始化時,會透過 ServiceLoader 掃描並自動載入所有聲明的驅動。
// mysql-connector-j-8.0.33.jar 中的 META-INF/services/java.sql.Driver 內容:
com.mysql.cj.jdbc.Driver
最佳實踐: 直接呼叫 DriverManager.getConnection(url, user, pass) 即可,代碼更乾淨,符合規範。
Driver driver = new com.mysql.cj.jdbc.Driver();
DriverManager.registerDriver(driver);
// 或者使用 DriverManager.deregisterDriver(driver) 反註冊
以下代碼無法正常工作:
// 錯誤示範:僅載入類,不初始化
ClassLoader cl = Thread.currentThread().getContextClassLoader();
cl.loadClass("com.mysql.cj.jdbc.Driver"); // 只有載入,無靜態初始化
// 正確:載入並實例化 (觸發初始化)
cl.loadClass("com.mysql.cj.jdbc.Driver").newInstance();
// 等價於
Class.forName("com.mysql.cj.jdbc.Driver"); // 載入 + 連結 + 初始化
關鍵差異:
ClassLoader.loadClass():僅將類字節碼載入 JVM 記憶體,**不執行靜態初始化塊**。Class.forName():載入、連結、**初始化** (執行 static 塊)。DriverManager 類載入時,透過 ServiceLoader 讀取 META-INF/services/java.sql.Driver,實例化所有驅動並存入 registeredDrivers 列表。getConnection(url...) 時,遍歷已註冊驅動,呼叫 driver.acceptsURL(url) 找到第一個支援該 URL 的驅動。connect(url, props) 方法返回 Connection 物件。| 誤區 | 真相 |
|---|---|
| 必須寫 Class.forName | JDK 6+ 只要引入驅動 JAR 即可自動載入 |
| Class.forName 會建立連線 | 它只註冊驅動,連線由 DriverManager.getConnection 建立 |
| 多次呼叫會重複註冊 | 驅動靜態塊只執行一次;DriverManager 內部有去重邏輯 |
| 用 ClassLoader.loadClass 即可 | 不會觸發 static 區塊,驅動不會註冊,會報 "No suitable driver" |
Class.forName() 是早期 JDBC 規範下強制觸發驅動註冊的手段。理解其本質是**觸發類初始化以執行靜態註冊代碼**,有助於排查 "No suitable driver found" 等經典錯誤。現代開發 (JDK 6+) **請直接省略此行**,依賴標準 SPI 機制自動完成,代碼更簡潔、更標準。