一、正文:
有去看開源框架的童鞋,應該會經常看到如下代碼:Thread.currentThread().getContextClassLoader().loadClass(className),那這個和Class.forName(className)有什么區別?
帶着這個問題,筆者查了一些資料,現整理分享如下,如果不當之處還望斧正:
通常情況下,一個JVM中的所有類加載器被組織成一個層次結構,使得每一個類加載器(除了啟動整個JVM的原始類加載器)都有一個父加載器。當被要求加載一個類時,每一個類加載器都將先委托父加載器來加載,只有父加載器都不能成功加載時當前類加載器才會加載(即“雙親委派”機制,想了解這方面知識的,請參見“深入探討java類加載機制”)。在這種情況下,如下的委派鏈中:ClassLoader A -> System class loader -> Extension class loader -> Bootstrap class loader,委派鏈左邊的ClassLoader就可以很自然的使用右邊的ClassLoader所加載的類。但如果情況要反過來,是右邊的ClassLoader所加載的代碼需要反過來去找委派鏈靠左邊的ClassLoader去加載東西怎么辦呢?沒轍,parent delegation是單向的,沒辦法反過來從右邊找左邊的~
那有沒有這種逆向的加載場景呢?有!通常發生在有些JVM核心代碼必須動態加載由應用程序開發人員提供的資源時。以JNDI舉例:它的核心內容(從J2SE1.3開始)在rt.jar中的引導類中實現了,但是這些JNDI核心類可能加載由獨立廠商實現和部署在應用程序的classpath中的JNDI提供者。這個場景要求一個父類加載器(這個例子中的原始類加載器,即加載rt.jar的加載器)去加載一個在它的子類加載器(系統類加載器)中可見的類。此時通常的J2SE委托機制不能工作,解決辦法是讓JNDI核心類使用線程上下文加載器,從而有效建立一條與類加載器層次結構相反方向的“通道”達到正確的委托。
知識補充:每一個線程分配一個上下文類加載器(除非線程由本地代碼創建)。該加載器是通過Thread.setContextClassLoader()方法來設置。如果你在線程構造后不調用這個方法,這個線程將會從它的父線程中繼承上下文類加載器。如果你在整個應用中不做任何設置,所有線程將以系統類加載器作為它們自己的上下文加載器
二、參考鏈接
http://hllvm.group.iteye.com/group/topic/38709
http://tyrion.iteye.com/blog/1958814