關於線程上下文類加載器已經在以前學得比較透了,做爲一個收尾,這裏用日常J2EE開發時JDBC鏈接Mysql數據庫常見的一段代碼經過分析它的底層進一步加深對線程上下文類加載器的理解,因此先來將鏈接應用代碼寫上,注意:這裏不力求真正的去完成數據的鏈接,重在在分代碼,以下:html
說實話現在的工做重點是搞android的開發,再來看上面的這段代碼仍是很是之親切的,固然啦搞J2EE開發的那就不用多說了,屢見不鮮了,好,接下來先來分析第一行代碼:java
對於mysql驅動有兩個:mysql
而咱們使用的是第一個,對於forName方法目前咱們也比較清楚它的做用了,看一下它的源碼:android
既然會初始化"com.mysql.jdbc.Driver",那就跟到這個類裏面,看在初始化的時候幹了啥:web
對於類的初始化是位置類加載的第三個階段,這裏再來回憶一下其整個過程:面試
而類的初始化會導至類的static代碼【靜太代碼塊,靜態變量】獲得執行,因此:sql
因此此時會調用DriverManager.registerDriver()方法,可是在調用方法以前確定也得初始化DriverManager嘛,因此跟進去:數據庫
是否是如我們分析的這樣的呢,我們能夠debug看一下,先打上斷點:學習
嗯~~徹底正確!繼續分析:線程
跟進去:
這是加載JDBC的另一種方式,我們能夠打印一下該系統屬性:
接着往下執行:
因此最終會用這種方式去加載驅動,因此這個方法就是去執行了驅動的加載工做,流程再回到上一層:
註冊驅動裏面是如何作的呢?
接着回到主流程的第二句代碼:
細心的話能夠發現,這句話徹底木有Mysql的API竟然最後就能夠生成Mysql的一個鏈接,這底層是怎麼作到的呢?繼續跟蹤,先簡單看一下getConnection的javadoc:
接着看它的具體代碼實現:
這裏能夠打一個段點看一下第三個參數是否如所料:
嗯~~完成正確~~繼續往下分析:
繼續打斷點確認一下是否如預料:
我們debug看一下此時registeredDrivers的值是多少:
呃~~爲啥有兩個呢,我們第一句代碼不僅是指定了一個麼,以下:
這是由於現在的mysql版本會自動在這個目錄進行尋找並註冊驅動:
因此這裏須要注意,繼續往下:
好,這個細節很是重要,定位到它看一下:
想一想爲啥呢?命名空間!!!!可能這塊已經都忘得差很少了,由於不一樣的類加載器所加載的相同的類是不相等的,如以前【https://www.cnblogs.com/webor2006/p/9157847.html】咱們作實驗所示:
回到我們這個場景,因爲是SPI的場景,用戶能夠隨意去設置線程上下文類加載器,因此就有可能出現不等的狀況,這也是爲啥要作一個判斷的緣由之所在,繼續往下分析:
至此整個JDBC的建立鏈接的過程就已經分析完了,而類加載器這塊的全部知識都已經學完啦,至關之不易,想當初對於類的雙親委託機制只知道概念,每次面試官問到這個時也僅能回到出理論部分,通過這麼細緻的學習我想無論將來的面試仍是工做當中遇到類加載相關的問題應該是so easy的事啦!