關於jdbc的源碼解析 DriverManager 和 Driver的加載

注: 本系列文章使用JDK1.5 數據庫驅動版本 mysql-connector-java-5.1.8b

 

上一篇中分析了Class.forName(“com.mysql.jdbc.Driver”)幕後所做的事情,也就是在Driver實現類中的靜態塊和構造函數,本篇主要來分析一下靜態塊的一句代碼:DriverManager.registerDriver方法和其它相關的調用。
    registerDriver方法是一個靜態方法,它所要做的工作就是加載所有系統提供的驅動,並把它們添加到具體的類中,形成對象。同時還創建連接,是一個管理驅動的工具類。如果我們使用的是mysql,那麼加載的也就是它的驅動。
    此方法的源碼如下:

  1. public static synchronized void registerDriver(java.sql.Driver driver)  
  2.     throws SQLException {  
  3.     if (!initialized) {  //1  
  4.         initialize();  
  5.     }        
  6.     DriverInfo di = new DriverInfo();  
  7.     di.driver = driver;  
  8.     di.driverClass = driver.getClass();  
  9.     di.driverClassName = di.driverClass.getName();  
  10.     // Not Required -- drivers.addElement(di);  
  11.     writeDrivers.addElement(di);   
  12.     println("registerDriver: " + di);  
  13.     /* update the read copy of drivers vector */  
  14.     readDrivers = (java.util.Vector) writeDrivers.clone();  
  15. }  

一、初始化操作
1、看看1處的代碼,判斷是否初始化,這個判斷的變量是一個靜態全局boolean值,初始爲false
    private static boolean initialized = false;


如果此變量的值爲false那麼它將會進入初始化方法,源碼如下:

  1. static void initialize() {  
  2.         if (initialized) {  
  3.             return;  
  4.         }  
  5.         initialized = true;  
  6.         loadInitialDrivers();  
  7.         println("JDBC DriverManager initialized");  
  8.     }  

2、Initialize方法中判斷initialized值是否爲真(其實就是通過此boolean變量判斷是否已經初始化完成),之後設置initialized值爲true,接着又會調用另一個方法loadInitialDrivers() 同樣是靜態方法,用於調用系統類裝載器,裝載所有系統提供的驅動:
loadInitialDrivers()源碼:

  1. private static void loadInitialDrivers() {  
  2.         String drivers;  
  3.       
  4.         try {  
  5.         drivers = (String) java.security.AccessController.doPrivileged(  
  6.         new sun.security.action.GetPropertyAction("jdbc.drivers"));  
  7.         } catch (Exception ex) {  
  8.             drivers = null;  
  9.         }  
  10.           
  11.         // If the driver is packaged as a Service Provider,  
  12.         // load it.  
  13.         // Get all the drivers through the classloader   
  14.         // exposed as a java.sql.Driver.class service.  
  15.       
  16.      DriverService ds = new DriverService();  
  17.      // Have all the privileges to get all the   
  18.      // implementation of java.sql.Driver  
  19.      java.security.AccessController.doPrivileged(ds);  
  20.          println("DriverManager.initialize: jdbc.drivers = " + drivers);  
  21.         if (drivers == null) {  
  22.             return;  
  23.         }  
  24.         while (drivers.length() != 0) {  
  25.             int x = drivers.indexOf(':');  
  26.             String driver;  
  27.             if (x < 0) {  
  28.                 driver = drivers;  
  29.                 drivers = "";  
  30.             } else {  
  31.                 driver = drivers.substring(0, x);  
  32.                 drivers = drivers.substring(x+1);  
  33.             }  
  34.             if (driver.length() == 0) {  
  35.                 continue;  
  36.             }  
  37.             try {  
  38.                 println("DriverManager.Initialize: loading " + driver);  
  39.                 Class.forName(driver, true,  
  40.                   ClassLoader.getSystemClassLoader());  
  41.             } catch (Exception ex) {  
  42.                 println("DriverManager.Initialize: load failed: " + ex);  
  43.             }  
  44.         }  
  45.     }  

主要代碼分析:
    下面這段創建了一個內部類對象,創建此對象時,它會從系統服務中加載驅動

  1. DriverService ds = new DriverService();  

DriverService內部類的具體代碼:

  1. class DriverService implements java.security.PrivilegedAction {  
  2.         Iterator ps = null;  
  3.     public DriverService() {};  
  4.         public Object run() {  
  5.     ps = Service.providers(java.sql.Driver.class);  //從系統服務中加載驅動  
  6.     try {  
  7.            while (ps.hasNext()) { //遍歷驅動  
  8.                ps.next();  
  9.            } // end while  
  10.     } catch(Throwable t) {  
  11.         // Do nothing  
  12.     }  
  13.         return null;  
  14.     } //end run  
  15. //end DriverService  

 

此句代碼就是找到所有的擁有權限的java.sql.Driver的實現

  1. java.security.AccessController.doPrivileged(ds);  

下面這段,意思是得到系統屬性jdbc.drivers對應驅動的驅動名稱,使用了JAVA的安全許可

  1. drivers = (String) java.security.AccessController.doPrivileged(  
  2.         new sun.security.action.GetPropertyAction("jdbc.drivers"));  

再看看後面的判斷和循環
首先判斷驅動服務對象是否爲null,如果爲null則返回,否則進入while循環,這個循環會依次遍歷多個數據庫驅動,因爲jdbc:drivers會有多個數據庫驅動,驅動名是以:分割,接下來就是通過Class.forName依次裝載驅動類,在其中使用了ClassLoader.getSystemClassLoader()系統類裝載器。

  1. if (drivers == null) {  
  2.             return;  
  3.         }  
  4.  while (drivers.length() != 0) {  
  5. …  
  6. Class.forName(driver, true, ClassLoader.getSystemClassLoader());  
  7. …  
  8. }  

上面分析的就是在registerDriver方法中所要做的第一件事情:初始化。可以看到initialize()做的工作就是裝載驅動,同時還需要使用到系統的一些功能。如: java.security.AccessController.doPrivileged,此方法允許在一個類實例中的代碼通知這個AccessController,它的代碼主體享受特權(Privileged),它不管這個請求是由什麼代碼所引發的,只是單獨負責對它可得到的資源的訪問請求。比如說,一個調用者在調用doPrivileged方法時,可被標識爲特權。AccessController做訪問控制決策時,如果checkPermission方法遇到一個通過doPrivileged方法調用而被視爲特權調用者,那麼checkPermission方法不會作許可檢查,表示那個訪問請求是被允許的,如果調用者沒有許可,則會拋出一個異常。

如:ClassLoader.getSystemClassLoader(),java中所有類都是通過ClassLoader裝載的,ClassLoader可以爲java程序提供很好的動態特性,有必要去深入理解哦。

接下來再看初始化之後的代碼:

  1. DriverInfo di = new DriverInfo();  
  2.     di.driver = driver;  
  3.     di.driverClass = driver.getClass();  
  4.     di.driverClassName = di.driverClass.getName();  
  5.     // Not Required -- drivers.addElement(di);  
  6.     writeDrivers.addElement(di);   
  7.     println("registerDriver: " + di);  
  8.     /* update the read copy of drivers vector */  
  9.     readDrivers = (java.util.Vector) writeDrivers.clone();  

創建DriverInfo對象
DriverInfo di = new DriverInfo();
DriverInfo驅動信息類,是一個內部類,
源碼如下:

  1. class DriverInfo {  
  2.     Driver         driver;  
  3.     Class          driverClass;  
  4.     String         driverClassName;  
  5.     public String toString() {  
  6.     return ("driver[className=" + driverClassName + "," + driver + "]");  
  7.     }  
  8. }  

此類就是添加了三個屬性,分別表示驅動對象,驅動的Class對象,以及驅動的類名;同時重寫了toString方法。此內部類的作用就是以可以創建DriverInfo對象,以對象的形式保存驅動信息。

接下來就是設置對象的三個屬性:

  1. DriverInfo di = new DriverInfo();  
  2. di.driver = driver;  
  3. di.driverClass = driver.getClass();  
  4. di.driverClassName = di.driverClass.getName();  

然後添加到集合writeDrivers中,這個集合是Vector類型,定義爲DriverManager的屬性

writeDrivers定義:

  1. private static java.util.Vector writeDrivers = new java.util.Vector();  

驅動添加到集合

  1. writeDrivers.addElement(di);  

最後就是調用writeDrivers對象的clone方法

  1. readDrivers = (java.util.Vector) writeDrivers.clone();  


readDrivers也是一個類型爲Vector的集合,定義爲DriverManager的屬性

  1. 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 中也有詳細描述。
這就是初始化的全過程,寫了這麼多,實際上只做一件事情,就是完成所有驅動的加載。裝載之後就是連接了,在連載三當中我會詳細描述。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章