java疫苗之殤?關於java類載入器的一些思考

vipshop_fin_dev發表於2018-07-29

近日疫苗之殤鬧得沸沸揚揚,究其原因是因為長春長生生物公司隨意改動製藥工藝,不管注射了這種疫苗會不會對身體有太大的影響,但是這嚴重影響了國民對醫藥的信任,可能導致國民不願注射疫苗,對傳染病防控帶來極大打擊,對公眾的生命安全帶來極大的風險。

對於此事,java王國卻在偷樂,他們早就有一個完善的方案來避免這種事情發生。從上到下,java王國政府都建有大大小小的藥廠,它們管這些藥廠叫做ClassLoader(類載入器),其中全國最大、最權威的藥廠叫做Bootstrap ClassLoader,次大一點的藥廠叫做Extension ClassLoader,這兩個藥廠管理著java王國裡面對公眾生命安全最重要、最基本的藥物。當然了java王國貴為程式語言第一大國,僅靠這兩家廠生產和管理這些藥物是遠遠不夠的,對於那些不那麼重要的藥,不會對公眾健康造成很大影響的藥物,java王國允許他們建造自己的ClassLoader,這些ClassLoader叫做Application ClassLoader,那麼這一小部分人就可以使用這個藥房的藥了。以上的藥廠都屬於中央或者地方政府的製藥工廠。然後接下來,對於那些實力強勁的企業如java第一集團apache旗下子公司tomcat,他們完全有能力自己製藥,自定義classLoader,並且能獲得舉國上下的認可和使用。
這裡寫圖片描述

他們實行了什麼政策可以保證疫苗的安全呢?他們出臺了“雙親委託模型”管理辦法,要求低一級的藥廠或者藥房在製造藥物的時候,必須交由它的上一級稽核和製造,如果上一級認為這種藥物不會危害生命,完全可以交由下級藥廠製造,那麼就會把這個申請打回下一級。

舉個例子,假如現在我想要一種叫做Object的藥,我會先到Application去買藥,而Application不管三七二十一,直接請求他的上級Extention ,而Extention ClassLoader也是同樣請求Bootstrap ,Bootstrap 發現這種藥是生命的必需藥物,當然應該由自己生產,於是就把Object藥物再逐層遞交到我手上。請求鏈是這樣的:Application–>Extention–>Bootstrap
這樣做有什麼用呢?可以防止一些不法分子生產危害系統的藥物,譬如有些不懷好意的人仿製了Object藥,並且這種藥具有破壞性,但是系統必須保證它使用的是Bootstrap 製造的,否則王國最基本的行為都無法保證了。

java王國做了這麼多事,無非就是想保證一個名稱空間。如何確定一個類的名稱空間呢?有一個辦法:載入它的類載入器,以及委託這個類載入器的子類載入器構成一個名稱空間。創造名稱空間主要是為了隔離不同名稱空間的類之間的互相影響。體現這點的一個例子就是Tomcat的類載入器:
這裡寫圖片描述
tomcat的類載入自己實現了Common、Catalina、Shared、WebApp等類載入器,主要是為了方便管理jar包。如放在tomcat的common資料夾下的jar包由Common ClassLoader載入,這會有什麼效果呢?這個tomcat下的每一個應用都可以使用common裡面的類了。而放在web app下的lib下的jar包,由於名稱空間只是webApp+jasper,因此僅限這個web app去訪問這個類。
當然凡事也有例外,為什麼這麼說呢。有時候有些大藥廠忙不過來,他們只會會定標準,讓下面的藥廠去實現,如JDBC。這些JDBC的標準介面就會由Bootstrap去載入,其名稱空間是Bootstrap,而具體的實現類可能由Application去載入(名稱空間為Application),那麼Bootstrap就無法找到JDBC的具體實現了。為此,java王國開闢了特別的通道:執行緒上下文的ClassLoader:Thread.currentThread().getContextClassLoader()。執行緒會藉此拿到當前執行緒上下文的ClassLoader去載入具體的JDBC的實現。
(完)

題外話
最近在讀spring的原始碼,發現一個方法ClassUtils#getDefaultClassLoader,是一個獲取類載入器的方法,這個方法寫得挺有意思,引起了對類載入器的一些回憶。於是就有了這篇文章。
這裡寫圖片描述
讀過周志明的<<深入瞭解java虛擬機器>>的(相信這是很多人接觸JVM的第一本讀物吧)會發現這其實就是裡面提到的雙親委託模型的第二次被破壞,它是由這個模型本身的缺陷所導致的。原文的內容是:
雙親委派模型的第二次“被破壞”是這個模型自身的缺陷所導致的,雙親委派模型很好地解決了各個類載入器的基礎類統一問題(越基礎的類由越上層的載入器進行載入),基礎類之所以被稱為“基礎”,是因為它們總是作為被呼叫程式碼呼叫的API。但是,如果基礎類又要呼叫使用者的程式碼,那該怎麼辦呢。

相關文章