Bootstrap Class Loader類加載器是JDK自帶的一款類加載器,用於加載JDK內部的類。Bootstrap類加載器用於加載JDK中$JAVA_HOME/jre/lib下面的那些類,好比rt.jar包裏面的類。Bootstrap類加載器是JVM的一部分,通常採用native代碼編寫。java
Extension Class Loader類加載器主要用於加載JDK擴展包裏的類。通常$JAVA_HOME/lib/ext下面的包都是經過這個類加載器加載的,這個包下面的類基本上是以javax開頭的。緩存
System Class Loader類加載器也叫應用程序類加載器(AppClassLoader)。顧名思義,這個類加載器就是用來加載開發人員本身平時寫的應用代碼的類的。System類加載器是用於加載存放在classpath路徑下的那些應用程序級別的類的。框架
類加載器之間經過這個層次關係協同工做,一塊兒負責類的加載工做。這種層次模型稱爲類加載器的「雙親委派」模型。雙親委派模型要求,除了最頂層的Bootstrap類加載器以外,全部的類加載器都必須有一個parent加載器。當類加載器加載類的時候,首先檢查緩存中是否有已經被加載的類。若是沒有,則優先委託它的父加載器去加載這個類,父加載器執行和前面子加載器同樣的工做,直到請求達到頂層的Bootstrap類加載器。若是父加載器不能加載須要的類,那麼這個時候纔會讓子加載器本身去嘗試加載這個類。這樣作的是由於防止加載到一些命令和lib中名字衝突的類。spa
上面講了那麼多類加載器相關的內容,可仍是沒有講到今天的主題,線程上下文類加載器。線程
到這裏,咱們已經知道Java提供了三種類加載器,而且按照嚴格的雙親委派機制協同工做。表面上,彷佛很完美,但正是這種嚴格的雙親委派機制致使在加載類的時候,存在一些侷限性。3d
當咱們更加基礎的框架須要用到應用層面的類的時候,只有當這個類是在咱們當前框架使用的類加載器能夠加載的狀況下咱們才能用到這些類。換句話說,咱們不能使用當前類加載器的子加載器加載的類。這個限制就是雙親委派機制致使的,由於類加載請求的委派是單向的。blog
雖然這種狀況很少,可是仍是會有這種需求。比較典型的,JNDI服務。JNDI提供了查詢資源的接口,可是具體實現由不一樣的廠商實現。這個時候,JNDI的代碼是由JVM的Bootstrap類加載器加載,可是具體的實現是用戶提供的JDK以外的代碼,因此只能由System類加載器或者其餘用戶自定義的類加載器去加載,在雙親委派的機制下,JNDI獲取不到JNDI的SPI的實現。繼承
爲了解決這個問題,引入了線程上下文類加載器。經過java.lang.Thread類的setContextClassLoader()設置當前線程的上下文類加載器(若是沒有設置,默認會從父線程中繼承,若是程序沒有設置過,則默認是System類加載器)。有了線程上下文類加載器,應用程序就能夠經過java.lang.Thread.setContextClassLoader()將應用程序使用的類加載器傳遞給使用更頂層類加載器的代碼。好比上面的JNDI服務,就能夠利用這種方式獲取到能夠加載SPI實現的類加載器,獲取須要的SPI實現類。接口
能夠看到,引入線程類加載器實際是對雙親委派機制的破壞,可是卻提供了類加載的靈活性。ssl