在使用傳統的JDBC串連資料庫的時候,總是需要這一句(以MySQL為例):
Class.forName("com.mysql.jdbc.Driver");
以前我也沒深究,只是看網上的例子都這麼寫,實際上也跑通了,於是便懶得去管內部原理。不過大概還是清楚的,知道這句話是向DriverManage註冊了一個MySQL的JDBC Driver。
但為什麼要用Class.forName這樣看上去不是很優雅的方式呢?
網上還流傳了一個這樣的版本Class.forName("com.mysql.jdbc.Driver").newInstance(),似乎有點兒多此一舉。
經過實驗,我發現用com.mysql.jdbc.Driver driver = new com.mysql.jdbc.Driver() 也是可以的,但是只聲明
com.mysql.jdbc.Driver driver = null ,而不執行個體化卻又是不行的。
那麼Driver的註冊到底是在類的初始化時進行的,還是在類的對象初始化時進行的呢? 我也不知道,最好的辦法還是看源碼:
package com.mysql.jdbc;
import java.sql.DriverManager;
import java.sql.SQLException;
// Referenced classes of package com.mysql.jdbc:
// NonRegisteringDriver
public class Driver extends NonRegisteringDriver
{
public Driver()
throws SQLException
{
}
static
{
try
{
DriverManager.registerDriver(new Driver());
}
catch(SQLException E)
{
throw new RuntimeException("Can't register driver!");
}
}
}
源碼之前沒秘密,com.mysql.jdbc.Driver很簡單,就是紅色的那句,看來是在類的static block裡面做的初始化。
那麼我們只要搞清楚在java裡面,static block執行的時機就可以清楚來龍去脈了。
還是做一個實驗吧:package com.javaye;
class A{
static{
System.out.println("Class A loaded");
}
public A(){
System.out.println("create a instance of A");
}
}
public class Main {
public static void main(String[] args) throws Exception{
Class.forName("com.javaye.A");
}
}
列印結果:“Class A loaded”
這說明Class.forName可以使類的static block中的代碼得到執行。
然後,我們在修改成下面這樣:
package com.javaye;
class A{
static{
System.out.println("Class A loaded");
}
public A(){
System.out.println("create a instance of A");
}
}
public class Main {
public static void main(String[] args) throws Exception{
com.javaye.A a = null;
}
}
發現沒有列印任何東西,這說明只是聲明某個類的變數,是不會使static block的到執行的。
再改一下:
package com.javaye;
class A{
static{
System.out.println("Class A loaded");
}
public A(){
System.out.println("create a instance of A");
}
}
public class Main {
public static void main(String[] args) throws Exception{
com.javaye.A a = new com.javaye.A();
com.javaye.A a2 = new com.javaye.A();
}
}
輸出結果:
Class A loaded
create a instance of A
create a instance of A
這說明執行個體化一個類的話,static block 也會被執行,而且只會被執行一遍。
如果仍有興趣,還可以探索一下Driver的註冊機制:
public static synchronized void registerDriver(java.sql.Driver driver)
throws SQLException {
if (!initialized) {
initialize();
}
DriverInfo di = new DriverInfo();
di.driver = driver;
di.driverClass = driver.getClass();
di.driverClassName = di.driverClass.getName();
drivers.addElement(di); //drivers 是一個vector,儲存著被註冊的driver.
println("registerDriver: " + di);
}
getConnection就是要從drivers裡面挑出一個合適的資料庫driver:
for (int i = 0; i < drivers.size(); i++) {
DriverInfo di = (DriverInfo)drivers.elementAt(i);
// If the caller does not have permission to load the driver then
// skip it.
if ( getCallerClass(callerCL, di.driverClassName ) != di.driverClass ) {
println(" skipping: " + di);
continue;
}
try {
println(" trying " + di);
Connection result = di.driver.connect(url, info);
if (result != null) {
// Success!
println("getConnection returning " + di);
return (result);
}
} catch (SQLException ex) {
if (reason == null) {
reason = ex;
}
}