一、定義
雙親委派模型要求除了頂層的啟動(dòng)類加載器外,其余的類加載器都應(yīng)當(dāng)有自己的父類加載器,這里的父子關(guān)系一般不會(huì)以繼承的關(guān)系實(shí)現(xiàn),而是使用組合關(guān)系來(lái)復(fù)用父加載器的代碼。
優(yōu)點(diǎn):1. Java類隨著類加載器一起具備了帶有優(yōu)先級(jí)的層次關(guān)系。
2. 避免類的重復(fù)加載
二、實(shí)現(xiàn)
如果一個(gè)類加載器收到了一個(gè)類加載的請(qǐng)求,首先檢查是否已經(jīng)被加載過(guò),如果沒(méi)有則調(diào)用父加載器的loadClass()方法,若父加載器為空,則默認(rèn)使用啟動(dòng)類加載器作為父加載器。如果父類加載失敗,則拋出ClassNotFoundException異常后,再調(diào)用自己的findClass()方法進(jìn)行加載。
三、破壞雙親委派模型
雙親委派模型并不是一個(gè)強(qiáng)制性的約束模型,而是Java設(shè)計(jì)者推薦給開(kāi)發(fā)者的實(shí)現(xiàn)方式。
雙親委派模型主要出現(xiàn)過(guò)3次“被破壞”情況。
1. 第一次被破壞發(fā)生在雙親委派模型出現(xiàn)之前,即JDK1.2發(fā)布之前。因?yàn)轭惣虞d器和抽象類java.lang.classLoader在JDK1.0時(shí)已經(jīng)存在,設(shè)計(jì)者為了向前兼容,在JDK1.2之后的java.lang.ClassLoader添加了一個(gè)新的protected方法的findClass()方法,該方法中實(shí)現(xiàn)的是自己的類加載邏輯,而loadClass()方法中實(shí)現(xiàn)的是雙親委派模型的具體邏輯。在loadClass()方法的邏輯里如果父類加載器加載失敗,則調(diào)用自己的findClass()方法來(lái)完成加載。
2. 第二次被破壞是由于模型自身缺陷導(dǎo)致的。在雙親委派模型中,越基礎(chǔ)的類由越上層的類加載器進(jìn)行加載,但如果基礎(chǔ)類又要調(diào)回用戶的代碼呢?比如JNDI服務(wù),它的代碼由啟動(dòng)類加載器加載,但JNDI是對(duì)資源進(jìn)行集中管理和查找,它需要調(diào)用由獨(dú)立廠商實(shí)現(xiàn)并部署在應(yīng)用程序的ClassPath下的JNDI接口提供者的代碼,但啟動(dòng)類加載器不可能認(rèn)識(shí)這些代碼。為此,Java設(shè)計(jì)者們引入了一個(gè)線程上下文類加載器。JNDI可以使用它加載所需要的SPI代碼。類似還有JDBC、JCE等。
3. 第三次破壞是由于用戶對(duì)程序動(dòng)態(tài)性的追求導(dǎo)致的。比如OSGI,它實(shí)現(xiàn)模塊化熱部署的關(guān)鍵則是它自定義的類加載器機(jī)制的實(shí)現(xiàn),每一個(gè)程序模塊都有一個(gè)自己的類加載器,當(dāng)需要更換一個(gè)模塊時(shí),就把模塊連同類加載器一起換掉以實(shí)現(xiàn)代碼的熱替換。在OSGi環(huán)境下,類加載器不再是雙親委派模型中的樹(shù)狀結(jié)構(gòu),而是進(jìn)一步發(fā)展為更加復(fù)雜的網(wǎng)狀結(jié)構(gòu)。