注: 本系列文章使用JDK1.5 數據庫驅動版本 mysql-connector-java-5.1.8b
上一篇中分析了Class.forName(“com.mysql.jdbc.Driver”)幕後所做的事情,也就是在Driver實現類中的靜態塊和構造函數,本篇主要來分析一下靜態塊的一句代碼:DriverManager.registerDriver方法和其它相關的調用。
registerDriver方法是一個靜態方法,它所要做的工作就是加載所有系統提供的驅動,並把它們添加到具體的類中,形成對象。同時還創建連接,是一個管理驅動的工具類。如果我們使用的是mysql,那麼加載的也就是它的驅動。
此方法的源碼如下:
- public static synchronized void registerDriver(java.sql.Driver driver)
- throws SQLException {
- if (!initialized) { //1
- initialize();
- }
- DriverInfo di = new DriverInfo();
- di.driver = driver;
- di.driverClass = driver.getClass();
- di.driverClassName = di.driverClass.getName();
- // Not Required -- drivers.addElement(di);
- writeDrivers.addElement(di);
- println("registerDriver: " + di);
- /* update the read copy of drivers vector */
- readDrivers = (java.util.Vector) writeDrivers.clone();
- }
一、初始化操作
1、看看1處的代碼,判斷是否初始化,這個判斷的變量是一個靜態全局boolean值,初始爲false
private static boolean initialized = false;
如果此變量的值爲false那麼它將會進入初始化方法,源碼如下:
- static void initialize() {
- if (initialized) {
- return;
- }
- initialized = true;
- loadInitialDrivers();
- println("JDBC DriverManager initialized");
- }
2、Initialize方法中判斷initialized值是否爲真(其實就是通過此boolean變量判斷是否已經初始化完成),之後設置initialized值爲true,接着又會調用另一個方法loadInitialDrivers() 同樣是靜態方法,用於調用系統類裝載器,裝載所有系統提供的驅動:
loadInitialDrivers()源碼:
- private static void loadInitialDrivers() {
- String drivers;
- try {
- drivers = (String) java.security.AccessController.doPrivileged(
- new sun.security.action.GetPropertyAction("jdbc.drivers"));
- } catch (Exception ex) {
- drivers = null;
- }
- // If the driver is packaged as a Service Provider,
- // load it.
- // Get all the drivers through the classloader
- // exposed as a java.sql.Driver.class service.
- DriverService ds = new DriverService();
- // Have all the privileges to get all the
- // implementation of java.sql.Driver
- java.security.AccessController.doPrivileged(ds);
- println("DriverManager.initialize: jdbc.drivers = " + drivers);
- if (drivers == null) {
- return;
- }
- while (drivers.length() != 0) {
- int x = drivers.indexOf(':');
- String driver;
- if (x < 0) {
- driver = drivers;
- drivers = "";
- } else {
- driver = drivers.substring(0, x);
- drivers = drivers.substring(x+1);
- }
- if (driver.length() == 0) {
- continue;
- }
- try {
- println("DriverManager.Initialize: loading " + driver);
- Class.forName(driver, true,
- ClassLoader.getSystemClassLoader());
- } catch (Exception ex) {
- println("DriverManager.Initialize: load failed: " + ex);
- }
- }
- }
主要代碼分析:
下面這段創建了一個內部類對象,創建此對象時,它會從系統服務中加載驅動
- DriverService ds = new DriverService();
DriverService內部類的具體代碼:
- class DriverService implements java.security.PrivilegedAction {
- Iterator ps = null;
- public DriverService() {};
- public Object run() {
- ps = Service.providers(java.sql.Driver.class); //從系統服務中加載驅動
- try {
- while (ps.hasNext()) { //遍歷驅動
- ps.next();
- } // end while
- } catch(Throwable t) {
- // Do nothing
- }
- return null;
- } //end run
- } //end DriverService
此句代碼就是找到所有的擁有權限的java.sql.Driver的實現
- java.security.AccessController.doPrivileged(ds);
下面這段,意思是得到系統屬性jdbc.drivers對應驅動的驅動名稱,使用了JAVA的安全許可
- drivers = (String) java.security.AccessController.doPrivileged(
- new sun.security.action.GetPropertyAction("jdbc.drivers"));
再看看後面的判斷和循環
首先判斷驅動服務對象是否爲null,如果爲null則返回,否則進入while循環,這個循環會依次遍歷多個數據庫驅動,因爲jdbc:drivers會有多個數據庫驅動,驅動名是以:分割,接下來就是通過Class.forName依次裝載驅動類,在其中使用了ClassLoader.getSystemClassLoader()系統類裝載器。
- if (drivers == null) {
- return;
- }
- while (drivers.length() != 0) {
- …
- Class.forName(driver, true, ClassLoader.getSystemClassLoader());
- …
- }
上面分析的就是在registerDriver方法中所要做的第一件事情:初始化。可以看到initialize()做的工作就是裝載驅動,同時還需要使用到系統的一些功能。如: java.security.AccessController.doPrivileged,此方法允許在一個類實例中的代碼通知這個AccessController,它的代碼主體享受特權(Privileged),它不管這個請求是由什麼代碼所引發的,只是單獨負責對它可得到的資源的訪問請求。比如說,一個調用者在調用doPrivileged方法時,可被標識爲特權。AccessController做訪問控制決策時,如果checkPermission方法遇到一個通過doPrivileged方法調用而被視爲特權調用者,那麼checkPermission方法不會作許可檢查,表示那個訪問請求是被允許的,如果調用者沒有許可,則會拋出一個異常。
如:ClassLoader.getSystemClassLoader(),java中所有類都是通過ClassLoader裝載的,ClassLoader可以爲java程序提供很好的動態特性,有必要去深入理解哦。
接下來再看初始化之後的代碼:
- DriverInfo di = new DriverInfo();
- di.driver = driver;
- di.driverClass = driver.getClass();
- di.driverClassName = di.driverClass.getName();
- // Not Required -- drivers.addElement(di);
- writeDrivers.addElement(di);
- println("registerDriver: " + di);
- /* update the read copy of drivers vector */
- readDrivers = (java.util.Vector) writeDrivers.clone();
創建DriverInfo對象
DriverInfo di = new DriverInfo();
DriverInfo驅動信息類,是一個內部類,
源碼如下:
- class DriverInfo {
- Driver driver;
- Class driverClass;
- String driverClassName;
- public String toString() {
- return ("driver[className=" + driverClassName + "," + driver + "]");
- }
- }
此類就是添加了三個屬性,分別表示驅動對象,驅動的Class對象,以及驅動的類名;同時重寫了toString方法。此內部類的作用就是以可以創建DriverInfo對象,以對象的形式保存驅動信息。
接下來就是設置對象的三個屬性:
- DriverInfo di = new DriverInfo();
- di.driver = driver;
- di.driverClass = driver.getClass();
- di.driverClassName = di.driverClass.getName();
然後添加到集合writeDrivers中,這個集合是Vector類型,定義爲DriverManager的屬性
writeDrivers定義:
- private static java.util.Vector writeDrivers = new java.util.Vector();
驅動添加到集合
- writeDrivers.addElement(di);
最後就是調用writeDrivers對象的clone方法
- readDrivers = (java.util.Vector) writeDrivers.clone();
readDrivers也是一個類型爲Vector的集合,定義爲DriverManager的屬性
- private static java.util.Vector readDrivers = new java.util.Vector();
爲什麼要先添加到writeDrivers然後再 clone到readDrivers中呢?
writeDrivers和 readDrivers兩個都是驅動集合,無論是註冊驅動抑或是取消註冊,都是先對writeDrivers驅動集合中的數據進行添加或刪除,然後再把writeDrivers中的驅動都clone到readDrivers中,每次取出Driver並不是在writeDrivers中,而是在readDrivers中取得。那麼這兩個驅動集合便可以這樣理解,writeDrivers驅動集合負責註冊驅動和註銷驅動,readDrivers驅動集合負責提供可用的驅動對象,readDrivers中的驅動對象應該都是可用的。把二者分開,使用者就不需加任何判斷,很方便。
這裏又涉及到一個知識就是clone, 有興趣的朋友可以查看相關JAVA文檔,Thinking in java 中也有詳細描述。
這就是初始化的全過程,寫了這麼多,實際上只做一件事情,就是完成所有驅動的加載。裝載之後就是連接了,在連載三當中我會詳細描述。