面試必問:什么是雙親委派模型?
雙親委派模型是 Java 類加載器的一種工作模式,通過這種工作模式,Java 虛擬機將類文件加載到內存中,這樣就保證了 Java 程序能夠正常的運行起來。那么雙親委派模型究竟說的是啥呢?接下來我們一起來看。
1.類加載器
雙親委派模型針對的是 Java 虛擬機中三個類加載器的,這三個類加載器分別是:
- 啟動類加載器(Bootstrap ClassLoader)
- 擴展類加載器(Extension ClassLoader)
- 應用程序類加載器(Application ClassLoader)
如下圖所示:
這 3 個類加載器的作用如下。
1.1 啟動類加載器
啟動類加載器(Bootstrap ClassLoader)是由 C++ 實現的,它是用來加載 <JAVA_HOME>\jre\lib\rt.jar 和 resources.jar 等 jar 包的,如下圖所示:
接下來我們寫個代碼測試一下 rt 類加載器的打印:
以上程序的執行結果如下圖所示:
問題來了,為什么打印的不是“Bootstrap ClassLoader”而是 null 呢?這是因為啟動類加載器(Bootstrap ClassLoader)是由 C++ 實現的,而這個 C++ 實現的類加載器在 Java 中是沒有與之對應的類的,所以拿到的結果是 null。
1.2 擴展類加載器
擴展類加載器是用來加載 <JAVA_HOME>\jre\lib\ext 目錄下 jar 包的,如下圖所示:
接下來我們使用代碼來演示一下 ext 類加載器,示例代碼如下:
以上程序的執行結果如下圖所示:
1.3 應用程序類加載器
應用程序類加載器是用來加載 classpath 也就是用戶的所有類的,接下來我們寫代碼測試一下應用程序類加載器的打印,實現代碼如下:
以上程序的執行結果如下圖所示:
2.雙親委派模型
雙親委派模型的執行流程是這樣的:
1、當加載一個類時,會先從應用程序類加載器的緩存里查找相應的類,如果能找到就返回對象,如果找不到就執行下面流程;
2、在擴展加載器緩存中查找相應的類,如果能找到就返回對象,如果找不到就繼續下面流程;
3、在啟動類加載器中查詢相應的類,如果找到就返回對象,如果找不到就繼續下面流程;
4、在擴展加載器中查找并加載類,如果能找到就返回對象,并將對象加入到緩存中,如果找不到就繼續下面流程;
5、在應用程序類加載器中查找并加載類,如果能找到就返回對象,并將對象加入到緩存中,如果找不到就返回 ClassNotFound 異常。加載流程如下圖所示:
一般“雙親”指的是“父親”和“母親”,而在這里“雙親”指的是類加載類先向上找,再向下找的流程就叫做雙親委派模型。
3.優缺點分析
3.1 優點
雙親委派模型的優點有兩個:1、安全。2、避免重復加載。
3.1.1 安全
在安全方面的表現時,當使用雙親委派模型時,用戶就不能偽造一些不安全的系統類了,比如 jre 里面已經提供了 String 類在啟動類加載時加載,那么用戶自定義再自定義一個不安全的 String 類時,按照雙親委派模型就不會再加載用戶定義的那個不安全的 String 類了,這樣就可以避免非安全問題的發生了。
3.1.2 避免重復加載
使用雙親委派模型也可以避免一個類被重復加載,當一個類被加載之后,因為使用的雙親委派模型,這樣不會出現多個類加載器都將同一個類重復加載的情況了。
3.2 缺點
雙親委派模型的典型問題是加載 SPI 實現類的場景,比如 JNDI(Java Naming and Directory Interface,Java 命名與目錄接口)服務,它的代碼由啟動類加載器去加載(在 JDK 1.3 時放進 rt.jar),但 JNDI 的目的就是對資源進行集中管理和查找,它需要調用獨立廠商實現部部署在應用程序的 classpath 下的 JNDI 接口提供者(SPI, Service Provider Interface)的代碼,但啟動類加載器不可能“認識”之些代碼,這就雙親委派模型的問題,JDBC 也是同樣的問題。
總結
雙親委派模型是和 Java 中多個類加載器(啟動類加載器、擴展加載器、應用程序類加載器)的運行規則,通過這個(雙親委派模型)規則可以避免類的非安全問題和類被重復加載的問題,但它也遇到了一些問題,比如 JNDI 和 JDBC 不能通過這個規則進行加載,它需要通過打破雙親委派的模型的方式來加載。