初步理解java類加載器

  Java虛擬機載入Java類的步驟:
    Java文件經過編譯器編譯後變成字節碼文件(.class文件),
    類加載器(ClassLoader)讀取.class文件,並且轉換成java.lang.Class的一個實例,
    最後通過newInstance方法創建該類的一個對象。
    ClassLoader的作用就是根據一個類名,找到對應的字節碼,根據這些字節碼定義出對應的類,
    該類就是java.lang.Class的一個實例。
    
  類加載器的組織結構
      Java有三個初始類加載器,當Java虛擬機啓動時,它們會按照以下順序啓動:
          Bootstrap classloader  ——》extension classloader  ————》system classloader
      三者的關係:
          bootstrap classloader是extension classloader的parent,
          extension classloader是system classloader的parent。
          
    bootstrap classloader
      它是最原始的類加載器,並不是由Java代碼寫的,是由原生代碼編寫的。
      Java有一次編譯、所有平臺運行的效果,就是因爲它寫了一份功能相同,但針對不同平臺不同語言實現的底層代碼。
      它負責加載Java核心庫。
      可以運行以下代碼,看看自己本地的Java核心庫位置:
      
URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
      for( int i = 0; i < urls.length; i++){
          System.out.println(urls[i].toExternalForm());
      }


    extension classloader
        它用來加載JRE的擴展目錄( JAVA_HOME/jre/lib/ext或者java.ext.dirs系統屬性指定的)JAR的類包。
        因爲它是bootstrap classloader加載的,所以,當運行:
       
 ClassLoader extensionClassloader = ClassLoader.getSystemClassLoader.getParent();
        System.out.println("the parent of extension classloader:"+ extensionClassloader.getParent());

        
      輸出的是:the parent of extension classloader:null
      
    System classloader
        它用於加載classpath目錄下的jar包,我們寫的Java類,一般都是由它加載,除非自己制定個人的類加載器。
        
  全盤負責委託機制
      classloader加載類時,使用全盤負責委託機制,可以分開兩部分理解:全盤負責,委託
      
      全盤負責機制 :若類A調用了類B,則類B和類B所引入的所有jar包,都由類A的類加載器統一加載。
      
      委託機制:類加載器在加載類A時,會優先讓父加載器加載,
      當父加載器加載不到,再找父父加載器,一直找到bootstrap classloader,才自己去相關的路徑去尋找加載。
      以下是ClassLoader的源碼:
      
protected synchronized Class<?> loadClass(String name, boolean resolve)
          throws ClassNotFoundException {
          //first, check if the class has already been loaded
          Class c = findLoadedClass(name);
          if(c == null) {
              try {
                  if( parent != null ){
                      //從父加載器加載
                      c = parent.loadClass(name, false);
                  } else {
                      //從bootstrap loader加載
                      c = findBootstrapClassOrNull(name);
                  }
              } catch ( ClassNotFoundException e ) {
                  //ClassNotFoundException thrown if class not found
                  //from the non-null parent class loader
              }
              if (c == null) {
                  //if still not found, then invoke findClass in order
                  //to find the class
                  c = findClass(name);
              }
          }
          if (resolve) {
              resolvClass(c);
          }
          return c;
      }

      
  舉例說明,類加載器加載類A的過程:
    1.判斷是否已經加載過,在cache裏面查找,若有,跳7;否則下一步
    2.判斷當前加載器是否有父加載器,若無,則當前爲ext classloader,跳去4,否則,下一步
    3.請求父加載器加載該類,若加載成功,跳7;若不成功,即父加載器不能找到該類,跳2
    4.請求JVM的bootstrap classloader加載,若加載成功,跳7;若失敗,跳5
    5.當前加載器自己加載,若成功,跳7;否則,跳6
    6.拋出ClassNotFoundException
    7.返回Class
    
  編寫自己的類加載器
      Java加載類的過程,實質上是調用loadClass()方法,
      loadClass()中調用findLoadedClass()方法來檢查該類是否已經被加載過,
      如果沒有就會調用父加載器的loadClass(),如果父加載器無法加載該類,就調用findClass()來查找該類。
      
      所以需要新建MyClassLoader繼承java.lang.ClassLoader,重寫其中的findClass()方法。
      主要是重新設計查找字節碼文件的方案,然後調用definedClass來返回。
                      
                      
                      
                      
                      
      
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章