JDBC鏈接MySQL的代碼片段和執(zhí)行結(jié)果
Java15和JDBC 8.0.18
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.18</version>
</dependency>
public void driverTest() throws SQLException {
System.out.println(java.sql.Driver.class.getClassLoader());
System.out.println(java.sql.DriverManager.class.getClassLoader());
System.out.println(com.mysql.jdbc.Driver.class.getClassLoader());
Connection conn= DriverManager.getConnection("jdbc:mysql://localhost:3306", "root", "123456");
}
System.out.println打印的結(jié)果
jdk.internal.loader.ClassLoaders$PlatformClassLoader@48140564
jdk.internal.loader.ClassLoaders$PlatformClassLoader@48140564
jdk.internal.loader.ClassLoaders$AppClassLoader@55054057
上面System.out.println打印的結(jié)果很容易理解磺浙,com.mysql.jdbc.Driver是第三方提供的依賴由AppClassLoader加載宵睦,其父類java.sql.Driver是JDK自帶模塊被PlatformClassLoader加載摩疑。java.sql.DriverManage與java.sql.Driver相同凝垛。
注:JDK9之后用PlatformClassLoader代替ExtClassLoader加載器,用來加載JDK中的非核心模塊類肛真。
如何破壞雙親委派模型
深入DriverManager.getConnection源碼
Debug代碼趁猴,其中參數(shù)caller結(jié)果如下狮崩,是我們自定義調(diào)用DriverManager.getConnection的方法driverTest()的類。而這個自定義類的ClassLoader顯然是AppClassLoader丘薛。
那么嘉竟,繼續(xù)往下執(zhí)行時,callerCL會被賦值為AppClassLoader洋侨。if語句不會走到周拐,之后注冊的所有數(shù)據(jù)庫Driver都是基于callerCL來加載。
接下來分析如何破壞雙親委派模型:
- AppClassLoader加載我們定義的測試類DriverStudy凰兑;
- 調(diào)用DriverManager.getConnection時妥粟,委派給其父加載器PlatformClassLoader加載;
- getConnection中嘗試去加載第三方依賴的數(shù)據(jù)庫Driver時吏够,我們發(fā)現(xiàn)沒有使用此方法所在類的加載器PlatformClassLoader(因為類加載機制制約勾给,PlatformClassLoader也無法加載第三方類庫)滩报,而是通過參數(shù)傳入了測試類DriverStudy的加載器AppClassLoader,另外if語句的條件判斷也保證一旦callerCL為null(證明是BootClassLoader)或為PlatformClassLoader時播急,會被設(shè)置為上下文類加載器脓钾。
callerCL = Thread.currentThread().getContextClassLoader()。
-
上下文類加載器Debug顯示如下為AppClassLoader桩警。上下文類加載器顧名思義典型應(yīng)用就是被線程設(shè)置后加載應(yīng)用可训,可通過Thread.setContextClassLoaser()方法設(shè)置。
總結(jié)一下捶枢,PlatformClassLoader加載DriverManager握截,執(zhí)行g(shù)etConnection方法后,會顯示的找到PlatformClassLoader的子加載器AppClassLoader去加載第三方的依賴類烂叔。父加載器調(diào)用子加載器進行類的加載谨胞,這里打破了雙親委派模型。