소스 코드 분석 자바 클래스 로 더

14132 단어 자바종류로 더
참고 내용:
4.567917.자바 가상 머 신(JVM 고급 특성 과 최 적 실천)을 깊이 이해 하 는 주지 명 선생님
  • 상 실리콘밸리 JVM 교육 영상 깊이 이해-송 홍 강 선생님
  • 자바 의 클래스 로 더 구 조 는 다음 그림 과 같다 는 것 을 잘 알 고 있 습 니 다(JDK 8 및 이전,JDK 9 는 모듈 화 되 었 습 니 다).

    3 층 류 의 적재 기,부모 위임 체제 에 대해 본 고 는 더 이상 판 서 를 하지 않 고 독자 가 스스로 바 이 두 를 할 수 있다.
    그렇다면 JDK 의 소스 코드 에서 3 층 구조의 구체 적 인 실현 은 어 떨 까?
    Bootstrap ClassLoader(유도 클래스 로 더)
    유도 클래스 로 더 는 C++로 이 루어 집 니 다.자바 코드 가 아 닙 니 다.따라서 자바 코드 에 서 는 이러한 로 더 를 가 져 올 수 없습니다.
    일반적으로 클래스 로 더 는 네 가지(유도 류,확장 류,시스템 류 및 사용자 정의 클래스 로 더)로 나 뉘 지만,사실은 JVM 가상 컴퓨터 규범 에서 지원 하 는 두 가지 유형의 로 더 는 유도 클래스 로 더(Bootstrap ClassLoader)와 자체 정의 클래스 로 더(User-Defined ClassLoader)로 나 뉜 다.따라서 확장 클래스 와 시스템 클래스 를 사용자 정의 클래스 로 통칭 할 수 있다.

    Extension ClassLoader(확장 클래스 로 더)와 Appclass Loader(시스템 클래스 로 더)
    확장 클래스 로 더 와 시스템 클래스 로 더 는 자바 언어 로 작 성 됩 니 다.sum.misc.Launcher 의 두 내부 클래스 ExtClassLoader 와 AppClassLoader 로 구체 적 으로 실 현 됩 니 다.LaunchLacher 클래스 에 들 어가 보 겠 습 니 다.(이 종 류 는 Oacle jdk 에서 원본 코드 를 공개 하지 않 았 습 니 다.구체 적 인 소스 코드 를 볼 필요 가 있 는 독 자 는 open jdk 를 다운로드 하여 구체 적 인 소스 코드 를 볼 수 있 습 니 다.필 자 는 IDEA 역 컴 파일 후 생 성 된 코드 만 사용 하여 분석 합 니 다).
    우선 Laucncher 의 구조 방법:
    
    public Launcher() {
      Launcher.ExtClassLoader var1;
      try {
      	//         
       var1 = Launcher.ExtClassLoader.getExtClassLoader(); 
      } catch (IOException var10) {
       throw new InternalError("Could not create extension class loader", var10);
      }
    
      try {
      	//         
       this.loader = Launcher.AppClassLoader.getAppClassLoader(var1); 
      } catch (IOException var9) {
       throw new InternalError("Could not create application class loader", var9);
      }
    		//                         
      Thread.currentThread().setContextClassLoader(this.loader); 
      String var2 = System.getProperty("java.security.manager");
      if (var2 != null) {
       SecurityManager var3 = null;
       if (!"".equals(var2) && !"default".equals(var2)) {
        try {
         var3 = (SecurityManager)this.loader.loadClass(var2).newInstance();
        } catch (IllegalAccessException var5) {
        } catch (InstantiationException var6) {
        } catch (ClassNotFoundException var7) {
        } catch (ClassCastException var8) {
        }
       } else {
        var3 = new SecurityManager();
       }
    
       if (var3 == null) {
        throw new InternalError("Could not create SecurityManager: " + var2);
       }
    
       System.setSecurityManager(var3);
      }
    
     }
    
    Launcher 의 구조 방법 에서 Launcher.ExtClassLoader 형식의 부분 변수 var 1(여 기 는 역 컴 파일 된 변수 이름)을 정의 하고 Launcher.ExtClassLoader.getExtClassLoader()방법 으로 이 부분 변수 에 값 을 부여 하고 Launcher.AppClassLoader.getAppClassLoader(var 1)를 호출 하 는 것 을 볼 수 있 습 니 다.인 스 턴 스 변수(유형 은 Launcher.AppClassLoader)에 값 을 부여 합 니 다.시스템 클래스 에 값 을 부여 할 때 확장 클래스 로 더 를 매개 변수 로 전송 하 는 것 을 주의해 야 합 니 다.
    또한 구조 방법 에서 시스템 클래스 로 더 를 현재 스 레 드 의 컨 텍스트 클래스 로 설정 합 니 다.컨 텍스트 클래스 로 더 에 대해 서 는 기본 형식 으로 사용자 코드 를 호출 할 때 방법 부모 클래스 로 더 구역 에서 하위 클래스 로 더 를 요청 하여 클래스 로 더 를 완성 하 는 행위 입 니 다.주로 JDBC,JNDI 등 SPI 서비스 제공 자 인터페이스 에 사용 되 어야 합 니 다.여 기 는 자세히 전개 되 지 않 습 니 다.
    상기 소스 코드 중의**getExtClassLoader()와 getAppClassLoader()*방법 소스 코드 는 다음 과 같 습 니 다.
    getExtClassLoader()는 Launcher 의 내부 클래스 ExtClassLoader(확장 클래스 로 더)의 정적 방법 입 니 다.
    
    //   ExtClassLoader      
    private static volatile Launcher.ExtClassLoader instance;//         
    
    public static Launcher.ExtClassLoader getExtClassLoader() throws IOException {
    //        ,ExtClassLoader    double-checking          
       if (instance == null) { 
        Class var0 = Launcher.ExtClassLoader.class;
        synchronized(Launcher.ExtClassLoader.class) {
         if (instance == null) {
          instance = createExtClassLoader(); //   ExtClassLoader
         }
        }
       }
    
       return instance;
      }
    
    // createExtClassLoader()  
    private static Launcher.ExtClassLoader createExtClassLoader() throws IOException {
       try {
        return (Launcher.ExtClassLoader)AccessController.doPrivileged(new PrivilegedExceptionAction<Launcher.ExtClassLoader>() {
         public Launcher.ExtClassLoader run() throws IOException {
          File[] var1 = Launcher.ExtClassLoader.getExtDirs();
          int var2 = var1.length;
    
          for(int var3 = 0; var3 < var2; ++var3) {
           MetaIndex.registerDirectory(var1[var3]);
          }
    
          return new Launcher.ExtClassLoader(var1); //       
         }
        });
       } catch (PrivilegedActionException var1) {
        throw (IOException)var1.getException();
       }
      }
    
    // ExtClassLoader     
    public ExtClassLoader(File[] var1) throws IOException {
    			//              !!,                   
       super(getExtURLs(var1), (ClassLoader)null, Launcher.factory); 
       SharedSecrets.getJavaNetAccess().getURLClassPath(this).initLookupCache(this);
      }
    
    //   URLClassLoader     
    //                  ,             ExtClassLoader 
    public URLClassLoader(URL[] urls, ClassLoader parent, getParent()          null
           URLStreamHandlerFactory factory) {
      super(parent);
      // this is to make the stack depth consistent with 1.1
      SecurityManager security = System.getSecurityManager();
      if (security != null) {
       security.checkCreateClassLoader();
      }
      acc = AccessController.getContext();
      ucp = new URLClassPath(urls, factory, acc);
     }
    
    getAppClassLoader()는 Launcher 의 내부 클래스 AppClassLoader(시스템 클래스 로 더)의 정적 방법 입 니 다.
    
    public static ClassLoader getAppClassLoader(final ClassLoader var0) throws IOException {
       final String var1 = System.getProperty("java.class.path");
       final File[] var2 = var1 == null ? new File[0] : Launcher.getClassPath(var1);
       return (ClassLoader)AccessController.doPrivileged(new PrivilegedAction<Launcher.AppClassLoader>() {
        public Launcher.AppClassLoader run() {
         URL[] var1x = var1 == null ? new URL[0] : Launcher.pathToURLs(var2);
         return new Launcher.AppClassLoader(var1x, var0); //            ,              
        }
       });
      }
    // AppClassLoader     
    AppClassLoader(URL[] var1, ClassLoader var2) { 
     //    var2     getAppClassLoader()    var0, var0     Launcher          ExtClassLoader
     //  ExtClassLoader      ,      var2          ,       AppClassLoader      ExtClassLoader
       super(var1, var2, Launcher.factory);
       this.ucp.initLookupCache(this);
      }
    
    상기 두 가지 방법 을 통 해 확장 클래스 로 더 를 가 져 올 때 null(즉 유도 로 더)이 고 같은 종류의 로 더 는 계승(Inheritance)관계 인 것 처럼 보이 지만 실제로는 관 계 를 포함 하 는 지 설명 할 수 있다.하층부 캐리어 에는 상층 부 캐리어 의 인용 이 포함 되 어 있다.
    ClassLoader 추상 클래스
    상기 한 ExtClassLoader 와 AppClassLoader 는 모두 ClassLoader 류 에 계승 되 었 고 ClassLoader 추상 류 도 로드 체제 의 초석 이다.그 다음 에 우 리 는 이 유형 에 들 어가 서 그의 주요 방법 을 살 펴 보 자.
    public final classLoader getParent()
    이러한 종류의 로 더 를 되 돌려 주 는 슈퍼 클래스 로 더
    public Classloadclass(String name) throws ClassNotFoundException
    이름 이 name 인 클래스 를 불 러 오고 결 과 를 java.lang.Class 클래스 로 되 돌려 줍 니 다.클래스 를 찾 지 못 하면 ClassNotFoundException 이상 으로 돌아 갑 니 다.이 방법의 논 리 는 양친 위임 모델 의 실현 이다.
    protected class findClass(string name)throws ClassNotFoundException
    4
  • 바 이 너 리 이름 이 name 인 클래스 를 찾 고 결 과 를 자바.lang.Class 류 의 인 스 턴 스 로 되 돌려 줍 니 다.이것 은 보 호 받 는 방법 입 니 다.JVM 은 이 방법 을 다시 쓰 도록 격려 합 니 다.사용자 정의 로 더 는 부모 의뢰 체 제 를 따라 야 합 니 다.이 방법 은 부모 클래스 로 더 를 검사 한 후에 loadclast()방법 으로 호출 됩 니 다
  • JDK 1.2 이전에 사용자 정의 클래스 로 딩 할 때 항상 ClassLoader 클래스 를 계승 하고 loadClass 방법 을 다시 써 서 사용자 정의 클래스 로 딩 클래스 를 실현 합 니 다.그러나 JDK 1.2 이후 loadClass()방법 을 덮어 쓰 는 것 을 권장 하지 않 고 사용자 정의 클래스 로 딩 논 리 를 findClass()방법 에 쓰 는 것 을 권장 합 니 다.앞의 분석 을 통 해 알 수 있 듯 이 findClass()방법 은 loadclass()방법 에서 호출 되 었 습 니 다.loadclass()방법 에서 부모 로 딩 에 실패 하면 자신의 findClass()방법 으로 클래스 로 딩 을 완성 합 니 다.이렇게 하면 사용자 정의 클래스 로 더 도 부모 의뢰 모드 에 부합 하도록 보장 할 수 있다
  • 4.567917.주의해 야 할 것 은 ClassLoader 류 에서 findClass()방법의 구체 적 인 코드 논 리 를 실현 하지 못 한 것 이다.대신 ClassNotFoundException 이상 을 던 지 는 동시에 findClass 방법 은 보통 defineClass 방법 과 함께 사용 된다 는 것 을 알 아야 한다.일반적으로 사용자 정의 클래스 로 더 를 사용 할 때 ClassLoader 의 findClass()방법 을 직접 덮어 쓰 고 로 딩 규칙 을 작성 하여 로 딩 할 바이트 코드 를 가 져 와 흐름 으로 변환 한 다음 defineClass()방법 으로 클래스 의 Class 대상 을 생 성 합 니 다.
    protected final Class defineClass(String name, byte[] b, int off,int len)
    4.567917.주어진 바이트 배열 b 에서 Class 로 전환 하 는 인 스 턴 스 에 따라 off 와 len 매개 변 수 는 실제 Class 정보 가 by te 배열 에서 의 위치 와 길 이 를 나타 내 는데 그 중에서 by te 배열 b 는 ClassLoader 가 외부 에서 가 져 온 것 입 니 다.이것 은 보 호 받 는 방법 입 니 다.사용자 정의 ClassLoader 하위 클래스 에서 만 사용 할 수 있 습 니 다
  • defineClass()방법 은 byte 바이트 흐름 을 JVM 이 식별 할 수 있 는 cClass 대상(ClassLoader 에서 이 방법 논리 가 실현 되 었 음)을 분석 하 는 것 입 니 다.이 방법 을 통 해 class 파일 을 통 해 class 대상 을 예화 할 수 있 을 뿐만 아니 라 다른 방식 으로 class 이미 지 를 예화 할 수 있 습 니 다.예 를 들 어 네트워크 를 통 해 하나의 바이트 코드 를 받 을 수 있 습 니 다.그리고 byte 바이트 흐름 으로 전환 하여 해당 하 는 Class 대상 을 만 듭 니 다
  • defineClass()방법 은 보통 findClass()방법 과 함께 사용 합 니 다.일반적으로 사용자 정의 클래스 로 더 를 사용 할 때 ClassLoader 의 findClass()방법 을 직접 덮어 쓰 고 로 딩 규칙 을 작성 하여 염 을 불 러 올 바이트 코드 를 얻 은 후 흐름 으로 전환 한 다음 defineClass()방법 으로 클래스 를 만 드 는 Class 대상 을 호출 합 니 다.
  • protected final void resoiveClass(class c)
    4.567917.링크 가 지정 한 자바 클래스 입 니 다.이 방법 을 사용 하면 클래스 의 Class 대상 을 만 드 는 동시에 해석 할 수 있 습 니 다.앞에서 말 했 듯 이 링크 단 계 는 주로 바이트 코드 를 검증 하고 클래스 변수 에 메모 리 를 할당 하 며 초기 값 을 설정 하 는 동시에 바이트 코드 파일 의 기호 인용 을 직접 참조 로 변환 합 니 다protected final Class findLoadedClass(String name)
  • 이름 이 name 인 불 러 온 클래스 를 찾 아 자바.lang.class 류 의 인 스 턴 스 를 되 돌려 줍 니 다.이 방법 은 final 방법 으로 수정 할 수 없습니다
  • private final ClassLoader parent;
    4.567917.이것 도 ClassLoader 의 인 스 턴 스 입 니 다.이 필드 에 표 시 된 ClassLoader 는 이 ClassLoader 의 부모 라 고도 부 릅 니 다.클래스 를 불 러 오 는 과정 에서 classLoader 는 일부 요청 을 부모 에 게 맡 길 수 있 습 니 다이러한 방법 에 대해 서 는 일일이 펼 치지 않 고 주로 loadclass()와 findClass()를 살 펴 봅 니 다.
    loadClass()
    
    public Class<?> loadClass(String name) throws ClassNotFoundException {
    		// loadClass           loadClass,                 ,   false
      return loadClass(name, false); 
     }
    //          loadClass  
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException{// resolve:true->  class         
      synchronized (getClassLoadingLock(name)) {//     ,        
       //                   
       Class<?> c = findLoadedClass(name);
       if (c == null) {
        long t0 = System.nanoTime();
        //                ,              。
        try {
         //               
         if (parent != null) {
          //          ,         loadClass    (    )
          c = parent.loadClass(name, false);
         } else { 
         		 // parent == null:            
          c = findBootstrapClassOrNull(name);
         }
        } catch (ClassNotFoundException e) {
         // ClassNotFoundException thrown if class not found
         // from the non-null parent class loader
        }
    				//                   or            
        if (c == null) { 
         // If still not found, then invoke findClass in order
         // to find the class.
         long t1 = System.nanoTime();
         //          findClass()
         c = findClass(name);
    
         // this is the defining class loader; record the stats
         sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
         sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
         sun.misc.PerfCounter.getFindClasses().increment();
        }
       }
       if (resolve) {//         
        resolveClass(c);
       }
       return c;
      }
     }
    
    findClass()
    
    // ClassLoader  findClass()  
    rotected Class<?> findClass(String name) throws ClassNotFoundException {
      throw new ClassNotFoundException(name);
     }
    
    ClassLoader 에서 findCLass()방법 이 이상 을 직접 던 지 는 것 을 볼 수 있 기 때문에 구체 적 인 실현 은 하위 클래스 에서 재 작성 하여 이 루어 진 것 입 니 다.ClassLoader 의 하위 클래스 SecureClassLoader 의 하위 클래스 URLClassLoader 에서 이 방법 을 다시 썼 습 니 다.
    URLClassLoader 의 findCLass()방법
    
    protected Class<?> findClass(final String name)
      throws ClassNotFoundException
     {
      final Class<?> result;
      try {
       result = AccessController.doPrivileged(
        new PrivilegedExceptionAction<Class<?>>() {
         public Class<?> run() throws ClassNotFoundException {
          String path = name.replace('.', '/').concat(".class");//            
          Resource res = ucp.getResource(path, false);//   class   
          if (res != null) {
           try {
           	//   defineClass()            Class  ,
           	// defineClass()          class          Class  
            return defineClass(name, res);
           } catch (IOException e) {
            throw new ClassNotFoundException(name, e);
           }
          } else {
           return null;
          }
         }
        }, acc);
      } catch (java.security.PrivilegedActionException pae) {
       throw (ClassNotFoundException) pae.getException();
      }
      if (result == null) {
       throw new ClassNotFoundException(name);
      }
      return result;
     }
    
    마지막 으로 배열 류 로 딩 에 대한 세부 사항 을 추가 합 니 다.
    그룹 클래스 의 Class 대상 은 클래스 로 더 가 만 든 것 이 아니 라 자바 실행 기 JVM 에서 필요 에 따라 자동 으로 만 듭 니 다.배열 류 의 클래스 로 더 에 있어 서 는 Class.getClassLoader()를 통 해 되 돌아 갑 니 다.배열 에 있 는 요소 형식의 클래스 로 더 와 같 습 니 다.배열 에 있 는 요소 형식 이 기본 데이터 형식 이 라면 배열 류 는 클래스 로 더 가 없습니다.
    자바 류 로 더 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 자바 류 로 더 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 응원 바 랍 니 다!

    좋은 웹페이지 즐겨찾기