5.3 Java類加載機制
Java的類加載機制稱作雙親委派機制,要明白JDBC為什么破壞雙親委派機制就需要明白雙親委派機制是什么,其作業原理如下,啟動類加載器BootStrap只加載rt.jar,也就是jdk提供的相關java部分,擴展類加載器只加載java lib/ext擴展目錄下的jar包,而用戶類加載器App加載用戶撰寫的代碼所在目錄(classpath),
Java加載類的整個程序是自頂向下的,當上級類加載器發現要加載的東西不屬于他的范圍,就讓下級類加載器去加載,這樣依次類推,

5.3.1 JDBC為什么要破壞雙親委派機制
通過上邊便已初見端倪,因為JDBC的DriverManager是由Bootstrap類加載器去加載的,呼叫的方法也是JDBC的方法,但是真正的驅動JDBC里根本沒有,所以在這樣的機制下Bootstrap類加載器不會向下委培自然也就加載不到了,所以要讓用戶程式類加載器來加載真正的驅動就需要打破這種機制,
5.3.2 如何實作打破雙親委派機制
獲取連接需要使用DriverManager的方法,該類在使用的時候會初始化執行loadInitialDrivers()方法來獲取真正的驅動,
- 使用DriverManager初始化驅動
static {
loadInitialDrivers();
println("JDBC DriverManager initialized");
}
- 初始化驅動loadInitialDrivers()方法
private static void loadInitialDrivers() {
String drivers;
try {
drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {
public String run() {
return System.getProperty("jdbc.drivers");
}
});
} catch (Exception ex) {
drivers = null;
}
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
//加載驅動,
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
Iterator<Driver> driversIterator = loadedDrivers.iterator();
try{
while(driversIterator.hasNext()) {
driversIterator.next();
}
} catch(Throwable t) {
// Do nothing
}
return null;
}
});
// ----------------------------分割線---------------------------------
println("DriverManager.initialize: jdbc.drivers = " + drivers);
if (drivers == null || drivers.equals("")) {
return;
}
String[] driversList = drivers.split(":");
println("number of Drivers:" + driversList.length);
for (String aDriver : driversList) {
try {
println("DriverManager.Initialize: loading " + aDriver);
Class.forName(aDriver, true,
ClassLoader.getSystemClassLoader());
} catch (Exception ex) {
println("DriverManager.Initialize: load failed: " + ex);
}
}
}
- load方法
public static <S> ServiceLoader<S> load(Class<S> service) {
//獲取當前執行緒的ClassLoader(用戶執行緒則是AppClassLoader)
ClassLoader cl = Thread.currentThread().getContextClassLoader();
return ServiceLoader.load(service, cl);
}
public static <S> ServiceLoader<S> load(Class<S> service,
ClassLoader loader)
{
return new ServiceLoader<>(service, loader);
}
- 設定classLoader
private ServiceLoader(Class<S> svc, ClassLoader cl) {
service = Objects.requireNonNull(svc, "Service interface cannot be null");
//開發者用戶執行緒classLoader
loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
reload();
}
5.3.3 DriverManager中的操作方法實體
獲取資料庫連接最后呼叫了getConnection(url, info, Reflection.getCallerClass()),傳入了一個反射獲取到的當前呼叫類,后邊會用的這個呼叫類的classLoader,
@CallerSensitive
public static Connection getConnection(String url,
String user, String password) throws SQLException {
java.util.Properties info = new java.util.Properties();
if (user != null) {
info.put("user", user);
}
if (password != null) {
info.put("password", password);
}
return (getConnection(url, info, Reflection.getCallerClass()));
}
在DriverManager中有一個很重要的方法判斷該驅動是否能被加載,
private static boolean isDriverAllowed(Driver driver, ClassLoader classLoader) {
boolean result = false;
if(driver != null) {
Class<?> aClass = null;
try {
//該classLoader能否加載到該類,加載到就回傳
aClass = Class.forName(driver.getClass().getName(), true, classLoader);
} catch (Exception ex) {
result = false;
}
//加載到該類再和驅動類比較是否同一個類,是則回傳true
result = ( aClass == driver.getClass() ) ? true : false;
}
return result;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/264893.html
標籤:java
上一篇:2021最新 QQqun乘員資料獲取專案(包含js逆向)——QQqunSpider [已完結]
下一篇:是啥時候轉換了編碼
