1. 程式人生 > >對ClassLoader的一些簡單總結

對ClassLoader的一些簡單總結

htm 執行者 post name har sstream str tuning 作用

參考:http://blog.csdn.net/briblue/article/details/54973413,http://blog.csdn.net/qbg19881206/article/details/8890600,http://zyjustin9.iteye.com/blog/2022654,https://www.cnblogs.com/tuning/p/6943427.html

一、ClassLoader的作用?

  ClassLoader翻譯過來就是類加載器。jvm啟動的時候,並不會一次性加載所有的class文件,而是根據需要去動態地加載。ClassLoader的作用就是將class文件加載到jvm虛擬機中去。

二、java自帶的三個類加載器

  1。Bootstrap ClassLoader。最頂層的加載類,主要加載核心類庫,加載%JRE_HOME%\lib下的rt.jar、resources.jar、charsets.jar和class等。

  2。Extention ClassLoader。擴展的類加載器,負責加載目錄%JRE_HOME%\lib\ext目錄下的jar包和class文件。

  3。Appclass Loader,也稱為SystemAppClass,加載當前應用的classpath的所有類。

  4。我們可以自己寫類加載器,加載類和資源。

三、類加載器間的關系

  AppClassLoader的父加載器是ExtClassLoader,ExtClassLoader的父加載器是Bootstrap ClassLoader。

  如果一個ClassLoader創建時如果沒有指定parent,那麽它的parent默認就是AppClassLoader。

四、類加載器的加載順序

  類加載器之間采用雙親委托的方式進行加載class。

  一個類加載器查找class和resource時,是通過“委托模式”進行的。它首先判斷這個class是不是已經加載,如果沒有的話就交給父加載器進行查找是否已加載,父加載器如果也沒有加載過,就交給更上層的類加載器查找,直至找到已加載這個class的類加載器,返回這個類,或者直到Bootstrap ClassLoader,如果Bootstrap classloader已加載,則直接返回,如果沒加載就進行查找。如果沒有找到,就交給下級加載器去查找加載,如果下級加載器沒有加載到,就交給下級去加載,加載到即返回,直至最下層的加載器。

五、線程的contextClassLoader

  1)contextClassLoader只是Thread類一個成員變量,通過setContextClassLoader()方法設置,通過getContextClassLoader()獲取。

  每個Thread都有一個相關聯的ClassLoader,默認是AppClassLoader。並且子線程默認使用父線程的ClassLoader,除非子線程特別設置。

  2)this.getClass.getClassLoader()和Thread.currentThread().getContextClassLoader()的區別

  方法一得到的Classloader是靜態的,表明類的載入者是誰;方法二得到的Classloader是動態的,誰執行(某個線程),就是那個執行者的Classloader,所以子線程默認使用父線程的ClassLoader。對於單例模式的類,靜態類等,載入一次後,這個實例會被很多程序(線程)調用,對於這些類,載入的Classloader和執行線程的Classloader通常都不同。

六、獲得ClassLoader的3種方法

  this.getClass().getClassLoader(); // 使用當前類的ClassLoader。
  Thread.currentThread().getContextClassLoader(); // 使用當前線程的ClassLoader。
  ClassLoader.getSystemClassLoader(); // 使用系統ClassLoader,JVM下system ClassLoader通常為App ClassLoader。

七、class.getName()等方法

  當你使用class.forName(),class.getName(),class.getResource()這幾個不帶ClassLoader參數的方法時,默認使用當前類的ClassLoader。

八、類加載器的getResource()方法

  1.this.getClass().getResource("");//得到當前類class文件的URI目錄。

  2.this.getClass().getResource("/");//得到當前的classpath的絕對URI路徑。

  3.this.getClass().getClassLoader().getResource("");//得到當前ClassPath的絕對URI路徑。

  4.ClassLoader.getSystemResource("");//得到的當前ClassPath的絕對URI路徑。

  5.Thread.currentThread().getContextClassLoader().getResource("");得到當前ClassPath的絕對URI路徑。

  Class.getResourse()和Class.getClassLoader().getResource()
  這兩個getResource()是使用當前ClassLoader加載資源(即資源在classpath中),這樣資源和class直接打在jar包中,避免文件路徑問題。兩者不同是Class的getResource()方法是從當前class文件路徑查找資源,ClassLoader則是從jar包根目錄查找。

九、用Classloader載入資源

  所有資源都通過ClassLoader載入到JVM裏,那麽在載入資源時當然可以使用ClassLoader。只是對於不同的資源還可以使用一些別的方式載入,例如對於類可以直接new,對於文件可以直接做IO等。

  1)實例化類B的三種方案

  1. 使用Class靜態方法 Class.forName

  Class cls = Class.forName("com.rain.B");

  B b = (B)cls.newInstance();

  2. 使用ClassLoader

  ClassLoader cl;//可以用前面提到的幾種方法

  Class cls = cl.loadClass("com.rain.B"); // 使用第一步得到的ClassLoader來載入B

  B b = (B)cls.newInstance(); // 有B的類得到一個B的實例

  3. 直接new

  B b = new B();

  2)文件載入(例如配置文件等)假設在com.rain.A類裏想讀取文件夾 /com/rain/config 裏的文件sys.properties,讀取文件可以通過絕對路徑或相對路徑,絕對路徑很簡單,在Windows下以盤號開始,在Unix下以"/"開始。對於相對路徑,其相對值是相對於ClassLoader的,因為ClassLoader是一棵樹,所以這個相對路徑和ClassLoader樹上的任何一個ClassLoader相對比較後可以找到文件,那麽文件就可以找到。

  1. 直接IO

  File f = new File("C:/test/com/rain/config/sys.properties"); // 使用絕對路徑

  //File f = new File("com/rain/config/sys.properties"); // 使用相對路徑

  InputStream is = new FileInputStream(f);

  2. 使用ClassLoader

   因為有3種方法得到ClassLoader,對應有如下3種方法讀取文件。 使用的路徑是相對於這個ClassLoader的那個點的相對路徑,此處只能使用相對路徑

  InputStream is = null;

  is = this.getClass().getClassLoader().getResourceAsStream("com/rain/config/sys.properties"); //方法1

  //is = Thread.currentThread().getContextClassLoader().getResourceAsStream("com/rain/config/sys.properties"); //方法2

  //is = ClassLoader.getSystemResourceAsStream("com/rain/config/sys.properties"); //方法3

對ClassLoader的一些簡單總結