Class.forName解析以及使用

這個類在剛學習Java鏈接數據庫的時候見到這個這種寫法,而且工做這麼多年,也許是接觸的東西比較少,這種用法也就只有在本身手寫數據庫鏈接代碼的時候見過,在其餘的時候還真是沒見過。java

在Class類中,對此方法有以下聲明mysql

方法重載了三次。sql

查看第一個forName方法的聲明爲:數據庫

@CallerSensitive
public static Class<?> forName(String className)
            throws ClassNotFoundException {
    Class<?> caller = Reflection.getCallerClass();
    return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}

首先在這個方法中,使用到了Reflection.getCallerClass(),返回是調用者對象框架

針對getCallerClass這個方法,這個方法是native的,聲明以下:函數

@CallerSensitive
public static native Class getCallerClass();

因爲是native方法,就暫時不跟進去了,這個方法的意思返回調用者 class對象),也就是說是誰調用調用了我這個類的方法。以下示例:學習

public class ReflectionCaller {
    public static void main(String[] args) {
        InnerClass i = new InnerClass();
        i.innerMethod();
    }
}

class InnerClass {
    public void innerMethod() {
        System.out.println(Reflection.getCallerClass());
    }
}

運行以上代碼,輸出的結果是:ui

也就是ReflectionCaller這個類對象。這個方法仍是比較有趣的,若是在之後咱們本身寫代碼的時候,想知道誰在調用我這些的這些方法,就能夠跟蹤出來了。spa

獲取調用者信息之後,會調用Class.forname0方法,進行加載和初始化類。看到forname0這個方法又是一個native方法。線程

private static native Class<?> forName0(String name, boolean initialize,
                                        ClassLoader loader,
                                        Class<?> caller)
    throws ClassNotFoundException;

這個方法的做用是根據name加載傳遞過來的類,而且根據initialize來決定是否要進行初始化,所謂初始化指的是加載裏面的靜態塊之類的。加載的時候採用caller相同的類加載器記性加載。

 

從中能夠看出Class.forName和Classloader.lodeclass的區別是什麼,Class.forName能夠加載類而且控制是否要對類進行初始化,而ClassLoader.loadClass只對類進行加載,不進行初始化。

 

知道了Class.forName 的做用,那接下來就看一下針對鏈接mysql的具體問題。

根據第一節,能夠看到鏈接字符串爲:

Class.forName("com.mysql.jdbc.Driver");

也就是說會加載com.mysql.jdbc.Driver這個類,而且進行初始化。找到mysql-connector-java.jar的源碼,這個類很是簡單。

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    //
    // Register ourselves with the DriverManager
    //
    static {
        try {
            java.sql.DriverManager.registerDriver(new Driver());
        } catch (SQLException E) {
            throw new RuntimeException("Can't register driver!");
        }
    }

    /**
     * Construct a new driver and register it with DriverManager
     * 
     * @throws SQLException
     *             if a database error occurs.
     */
    public Driver() throws SQLException {
        // Required for Class.forName().newInstance()
    }
}

這個類中 就一個靜態塊和一個無參的構造函數,經過靜態塊的內容能夠看出,實例了的一個Driver,而後註冊到DriverManagerDriverManager把這個Driver存儲到了一個CopyOnWriteArrayList中。

同時Driver還繼承了AbandonedConnectionCleanupThread這個類,這個類繼承Thread,啓動一個守護線程,而後清理廢棄的類對象。

以上就是咱們在鏈接mysql時,Class.forName的功能。可是須要注意的是 Java 的SQL框架容許多個數據庫的Driver,每個Driver都要實現java.sql.Driver接口,針對給出來的鏈接數據庫的請求,DriverManager嘗試去load儘量多的它找到的drivers,而後根據這些driver嘗試使用給出來的數據庫鏈接字符串去嘗試鏈接數據庫。 在mysql的NonRegisteringDriver中強烈建議,每一個驅動程序類應該儘量的小和獨立,這樣在加載和查詢驅動類的時候,纔不會引入大量的支持代碼。

相關文章
相關標籤/搜索