Thread.currentThread().getContextClassLoader() 和 Class.getClassLoader()區別
查了一些資料也不是太明白兩個的區別,但是前者是最安全的用法
|
1
2
3
4
5
6
7
8
9
10
11
|
public
class
Test {
public
static
void
main(String[] args) {
// 此時三個ClassLoader是同一個對象
System.out.println(Thread.currentThread().getContextClassLoader());
// 當前線程的類加載器
System.out.println(Test.
class
.getClassLoader());
// 當前類的類加載器
System.out.println(ClassLoader.getSystemClassLoader());
// 系統初始的類加載器
}
}
|
如果樓主了解過openfire應該對ClassLoader有比較深的理解。
打個簡單的比方,你一個WEB程序,發布到Tomcat里面運行。
首先是執行Tomcat org.apache.catalina.startup.Bootstrap類,這時候的類加載器是ClassLoader.getSystemClassLoader()。
而我們后面的WEB程序,里面的jar、resources都是由Tomcat內部來加載的,所以你在代碼中動態加載jar、資源文件的時候,首先應該是使用Thread.currentThread().getContextClassLoader()。如果你使用Test.class.getClassLoader(),可能會導致和當前線程所運行的類加載器不一致(因為Java天生的多線程)。
Test.class.getClassLoader()一般用在getResource,因為你想要獲取某個資源文件的時候,這個資源文件的位置是相對固定的。
java的類加載機制(jvm規范)是委托模型,簡單的說,如果一個類加載器想要加載一個類,首先它會委托給它的parent去加載,如果它的所有parent都沒有成功的加載那么它才會自己親自來,有點兒像兒子使喚老子的感覺。。jvm也拼爹啊,,,,,
在jvm中默認有三類loaer,bootstrap,ext,app,其中boot最大是爺爺,app最小是孫子,ext中間是爹。
它們有權限訪問的classpath也不一樣,boot是jdk或jre下面的lib目錄,ext是jdk或jre的ext目錄,而app是由用戶指定的路徑,比如用-cp參數指定的目錄或jar。他們沒有權力訪問其他人的classpath,這樣問題就來鳥,,,,可能有人會問狗司令大人閑得蛋疼啊,搞這么復雜,據說是為了安全考慮,避免用戶的惡心意代碼侵蝕jvm,,問題就是當bootstrap或ext想要加載用戶指定classpath中的類就會失敗,因為這倆貨沒有權限訪問團app路徑中的類的,,所以就搞了這么一個不倫不類的contextloader。。。。
