Class.forName載入資料庫驅動深入探討
最近寫了個監控系統,需要從各個資料庫中獲取資料,為了可配行,各個資料庫的資訊(資料庫型別,使用者名稱,密碼等)都存放在我們自己的資料庫中,
暫時想到的方法就是直接用JDBC程式碼訪問資料庫,取資料,然後將資料庫連線進行池化。
唉,以前都是J2EE開發,用spring配置使用,這次直接使用JDBC還不太習慣了,OK,不廢話了
JDBC步驟:
1.載入資料驅動
Class.forName("com.mysql.jdbc.Driver");
2. 得到資料庫連線
DriverManager.getConnection(url, user, password);
當時到這步就產生兩個疑問:
1. 為什麼載入了資料庫驅動,就能得到資料庫連線,看上面的兩行程式碼,是看出來兩者之間聯絡
2. 除了Class.forName()載入資料庫驅動,貌似沒有看到過其他載入資料庫驅動方式,是否有其他方式?為什麼不用其他方式?
OK,問題出來了,就看看問題
問題1:
後來結合資料庫驅動原始碼和JDBC規範瞭解到,每個資料庫驅動,都必須在載入的時候,自己實現資料庫驅動註冊(註冊?貌似前面觀察者模式就有註冊行為,但是資料庫驅動卻沒有update行為,所以不存在通知)
mysql驅動原始碼:
public class Driver extends NonRegisteringDriver implements java.sql.Driver { public Driver() throws SQLException { } static { try { DriverManager.registerDriver(new Driver()); } catch (SQLException E) { throw new RuntimeException("Can't register driver!"); } } }
DriverManager.registerDriver()程式碼如下:
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(); // Not Required -- drivers.addElement(di); writeDrivers.addElement(di); println("registerDriver: " + di); /* 由於可以註冊多個數據庫驅動型別,這裡更新下資料庫驅動 */ readDrivers = (java.util.Vector) writeDrivers.clone(); }
這樣在DriverManager.getConnection()的時候,就可以用到資料庫驅動,得到連線了,程式碼如下
public static Connection getConnection(String url,
String user, String password) throws SQLException {
java.util.Properties info = new java.util.Properties();
// Gets the classloader of the code that called this method, may
// be null.
ClassLoader callerCL = DriverManager.getCallerClassLoader();
if (user != null) {
info.put("user", user);
}
if (password != null) {
info.put("password", password);
}
return (getConnection(url, info, callerCL));
}
private static Connection getConnection(
String url, java.util.Properties info, ClassLoader callerCL) throws SQLException {
java.util.Vector drivers = null;
/*
* When callerCl is null, we should check the application's
* (which is invoking this class indirectly)
* classloader, so that the JDBC driver class outside rt.jar
* can be loaded from here.
*/
synchronized(DriverManager.class) {
// synchronize loading of the correct classloader.
if(callerCL == null) {
callerCL = Thread.currentThread().getContextClassLoader();
}
}
if(url == null) {
throw new SQLException("The url cannot be null", "08001");
}
println("DriverManager.getConnection(\"" + url + "\")");
if (!initialized) {
initialize();
}
synchronized (DriverManager.class){
// 得到註冊的驅動
drivers = readDrivers;
}
// Walk through the loaded drivers attempting to make a connection.
// Remember the first exception that gets raised so we can reraise it.
SQLException reason = null;
for (int i = 0; i < drivers.size(); i++) {
DriverInfo di = (DriverInfo)drivers.elementAt(i);
// 根據資料庫型別判斷,得到這次請求的資料庫連線
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;
}
}
}
// if we got here nobody could connect.
if (reason != null) {
println("getConnection failed: " + reason);
throw reason;
}
println("getConnection: no suitable driver found for "+ url);
throw new SQLException("No suitable driver found for "+ url, "08001");
}
OK,到此問題的答案算是明白了
下面,問題2:
載入類的方式幾種,目前我想到的就下面幾種,不夠以後在補充,呵呵:
1. Class.forName()
2. Class.forName().newInstance();
3. new
4.Class.class
5.Class.class.newInstance();
6.Thread.currentThread().getContextClassLoader().loadClass()
可以知道方法2和5都是有點多餘,載入的類,還例項化了一個物件出來,可以Pass掉。而3跟前面一個問題一樣,例項化了一個物件出來,多此一舉,此物件還佔據記憶體。
OK,還剩下三種方法1.4.6,先來分析1和6的區別
Class.forName()的原始碼如下:
public static Class<?> forName(String className)
throws ClassNotFoundException {
return forName0(className, true, ClassLoader.getCallerClassLoader());
}
呼叫此方法等效於:
Class.forName(className, true, currentLoader)
第二次引數表示裝載類的時候是否初始化該類, 即呼叫類的靜態塊的語句及初始化靜態成員變數。
Thread.currentThread().getContextClassLoader().loadClass()的程式碼如下:
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
protected synchronized Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// First, check if the class has already been loaded
Class c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
此方法使用指定的二進位制名稱來載入類。此方法的預設實現將按以下順序搜尋類:
如果使用上述步驟找到類,並且 resolve 標誌為真,則此方法將在得到的 Class 物件上呼叫 resolveClass(Class)
方法。
- 引數:
-
resolve
- 如果該引數為 true,則分析這個類
所以此方法沒有初始化類,即沒有載入類的靜態程式碼,所以此方法不行
OK,下面只剩下方法1和4了,方法4載入類會獲得編譯檢查,可以保證此類一定存在,所以無法做到執行時動態載入未知資料庫驅動,並且Class.class前面還必須給一個變數賦值才行: Class cc = Class.class
所以載入資料庫,大家看到的都是方法1。
好了,到這,收工,呵呵。。。。
相關推薦
Class.forName載入資料庫驅動深入探討
最近寫了個監控系統,需要從各個資料庫中獲取資料,為了可配行,各個資料庫的資訊(資料庫型別,使用者名稱,密碼等)都存放在我們自己的資料庫中, 暫時想到的方法就是直接用JDBC程式碼訪問資料庫,取資料,然後將資料庫連線進行池化。 唉,以前都是J2EE開發,用spring配置使用,
為什麼使用Class.forName("")載入資料庫驅動
Class.forName(“”)返回的是類 Class.forName(“”).newInstance()返回的是object 有資料庫開發經驗朋友會發現,為什麼在我們載入資料庫驅動包的時候有的卻沒有呼叫newInstance( )方法呢?
由載入資料庫驅動的方法Class.forName()看其作用!
使用JDBC時,我們都會很自然得使用下列語句: java 程式碼 Class.forName("com.mysql.jdbc.Driver"); String url = "jdbc:mysql://127.0.0.1/test?useUnicode=true&am
Class.forName 如何載入資料庫驅動
一直有一個疑問,Class.forName(driverName)是如何完成載入資料庫驅動的,查閱了Oracle驅動的原始碼之後,大體弄清楚了。 我們知道,Class.forName所做的工作是載入指定的class檔案到java虛擬機器的記憶體,載入class檔案到記憶體的時候,該class檔案的靜態變數和
springboot啟動不能載入資料庫驅動Failed to determine a suitable driver class
1 SLF4J: Class path contains multiple SLF4J bindings. 2 SLF4J: Found binding in [jar:file:/G:/sharp/repo/ch/qos/logback/logback-classic/1.2.3/logback-
java Class.forName() 載入類
主要功能 Class.forName(xxx.xx.xx)返回的是一個類。 Class.forName(xxx.xx.xx)的作用是要求JVM查詢並載入指定的類,也就是說JVM會執行該類的靜態程式碼段。 在指定類給 forName() 方法後,如果找不到指定的類,會丟擲 ClassNo
Java反射中Class.forName()載入類和使用ClassLoader載入類的區別
最近在面試過程中有被問到,在Java反射中Class.forName()載入類和使用ClassLoader載入類的區別。當時沒有想出來後來自己研究了一下就寫下來記錄一下。 解釋 在java中Class.forName()和ClassLoader都可以對類進行載入。ClassLoader就是遵
[瘋狂Java]JDBC:載入資料庫驅動、連線資料庫
1. 載入資料庫驅動: 1) 由於Java是一個純面嚮物件語言,任何事物在其中都必須抽象成類或者類物件,資料庫也不例外,JDBC同樣也把資料庫抽象成面向物件的結構; 2) JDBC將整個資料庫驅動器在底層抽象成一個物件(即驅動器物件),所有對資料庫的操作都可
javaEE 中jdbc載入資料庫驅動失敗
jdbc連結mysql資料庫的時候 Class.forName("com.mysql.jdbc.Driver"); 這句報ClassNotFoundException,網上找了一下,這篇部落格講的非常實用,推薦給大家 http://blog.csdn.
thinkphp無法載入資料庫驅動: Think\Db\Driver\
今天做專案的時候加了配置檔案導致這個問題 很懵逼,上午跑的好好地, 1.首先在你輸出的頁面var_dump(C()); 打印出頁面載入的東西,檢視結果中是否缺失DB_TYPE等資料庫連線資料 最後
Java載入資料庫連線驅動為什麼要用Class.forName()方法?
靜態初始化過程,可以閱讀一下Thinking in Java 2nd 的第5-8章 JDBC提供的DriverManager類用於跟蹤所有可用的JDBC驅動,並在使用者需要時選擇合適的驅動提供給使用者 但是其跟蹤不是自動的,必須由可用的JDBC驅動
JDBC不再需要Class.forName()來顯式載入jdbc驅動
最近在用jdbc操作資料庫時,發現沒有Class.forName("com.mysql.jdbc.Driver")這一句,也可以連上資料庫並操作。後來在java.sql.DriverManager類中找到了這行註釋 * <P>Applications no lon
關於Java連線mysql資料庫驅動載入
第一步準備工作: 在官網https://dev.mysql.com/downloads/connector/j/下載mysql驅動 下載完後開啟資料夾 複製mysql-connector-java-8.0.13.jar檔案 第二步開啟e
Java中的類載入和Class.forName();java反射機制與原理
對於大部分人來說,第一次見到class.forName(String className)這句程式碼應該是在使用jdbc方式連線資料庫的時候。但這句程式碼本質上是什麼含義,做了什麼工作呢?本文將回答此問題。 理解Class.forName方法需要一些知識鋪墊,也就是
重新安裝了tomcat導致資料庫驅動載入不成功的解決方案
今天我運行了一下我的登入專案,發現執行不成功,加了斷點發現是驅動載入問題,想起了我昨天把tomcat解除安裝重灌,可能是重灌了以後把原本路徑下的jar包刪除了,但是我換了路徑build path了也不行,搞了半天也不知道為啥,我之前的一個application專案也用到資料庫
深入探討 Java 類載入器
類載入器是 Java 語言的一個創新,也是 Java 語言流行的重要原因之一。它使得 Java 類可以被動態載入到 Java 虛擬機器中並執行。類載入器從 JDK 1.0 就出現了,最初是為了滿足 Java Applet 的需要而開發出來的。Java Applet 需要從
spring boot 資料庫驅動 maven載入問題
問題描述:在2.0之後版本的spring boot 引用一些資料庫驅動會發現無法識別,再去maven下檢視會發現驅動未下載。 經過我的勘察,發現原來是因為,新版本的依賴 <parent> <groupId>org.springframewo
JDBC 連線資料庫 中Class.forName的作用
JAVA課上交過jdbc連線資料庫。可是老師也沒說當中 這樣的程式碼是什麼意思:Class.forName("com.mysql.jdbc.Driver");conn = DriverManager.getConnection(URL);很久前 看到一個面試題 大概也是問這幾
Java 類載入機制 ClassLoader Class.forName 記憶體管理 垃圾回收GC
類載入是Java程式執行的第一步,研究類的載入有助於瞭解JVM執行過程,並指導開發者採取更有效的措施配合程式執行。 研究類載入機制的第二個目的是讓程式能動態的控制類載入,比如熱部署等,提高程式的靈活性和適應性。 一、簡單過程 Java
註冊 Jdbc 驅動程式的三種方式及Class.forName 的作用
(1)jdbc中註冊驅動,首先匯入對應的包,例如mysql-connector-java-5.0.8-bin.jar。驅動包是java和具體資料庫之間的連線橋樑,由資料庫廠商開發。每一種資料庫對應一款驅動jar,甚至每一個版本的資料庫都有自己對應版本的驅動jar。 (2