java ClassLoader 메커니즘 상세 설명

5740 단어 javaClassLoader
ClassLoader를 깊이 있게 이해하려면 먼저 ClassLoader가 무엇을 하는지 알아야 한다. 말 그대로 Class 파일을 JVM에 불러와서 프로그램이 사용할 수 있도록 하는 것이다.우리는 자바 프로그램이 동적 로드 클래스를 정의할 수 있다는 것을 알고 있다. 이 동적 로드 메커니즘은 ClassLoader를 통해 이루어진 것이기 때문에 ClassLoader의 중요성이 어떠한지 알 수 있다.
여기를 보시면 어떤 분들은 질문을 하실 수 있습니다. 바로 ClassLoader가 JVM에 클래스를 불러오는 데 사용되기 때문에 ClassLoader는 어떻게 불러옵니까?설마 얘는 자바 클래스가 아니야?
틀림없습니다. 여기에는 확실히 하나의 ClassLoader가 자바 언어로 작성된 것이 아니라 JVM으로 이루어진 일부분입니다. 이 ClassLoader는 바로bootstrap classloader(시작 클래스 로더)입니다. 이 ClassLoader는 JVM이 실행될 때 자바 핵심의 API를 불러와서 자바 프로그램의 가장 기본적인 수요를 만족시킵니다. 그 중에서 사용자 정의인 ClassLoader를 포함합니다. 여기서 사용자 정의란 자바 프로그램을 통해 이루어진 ClassLoader를 가리킵니다.하나는 ExtClassLoader입니다. 이 ClassLoader는 자바의 확장 API를 불러오는 데 사용됩니다. 즉,/lib/ext의 클래스입니다. 하나는 AppClassLoader입니다. 이 ClassLoader는 사용자 기기의 CLASSPATH 설정 디렉터리에 있는 Class를 불러오는 데 사용됩니다. 보통 ClassLoader를 지정하지 않은 상황에서 프로그래머가 사용자 정의한 클래스는 이 ClassLoader에서 불러옵니다.
프로그램을 실행할 때 JVM이 시작하고 bootstrap classloader를 실행합니다. 이 ClassLoader는 자바 핵심 API(ExtClassLoader와 AppClassLoader도 이때 불러옵니다)를 불러오고 ExtClassLoader를 호출하여 확장 API를 불러옵니다. 마지막으로 AppClassLoader는 CLASSPATH 디렉터리에 정의된 Class를 불러옵니다. 이것이 프로그램의 가장 기본적인 불러오는 절차입니다.
위에서 ClassLoader의 역할과 가장 기본적인 로드 절차를 대충 설명했습니다. 다음은 ClassLoader의 로드 방식을 설명할 것입니다. 여기서 ClassLoader가 양친 의뢰 모드를 사용하여 클래스 로드를 진행했다는 것을 설명할 수 밖에 없습니다.
모든 사용자 정의 ClassLoader는 반드시 ClassLoader라는 추상적인 클래스를 계승해야 한다. 모든 ClassLoader는 parent ClassLoader를 가지고 있다. 우리는 ClassLoader라는 추상적인 클래스 중 getParent() 방법이 있다. 이 방법은 현재 ClassLoader의 parent를 되돌려 주는 데 사용된다. 이 parent는 계승된 클래스가 아니라 이 ClassLoader를 실례화할 때 지정한 ClassLoader를 가리킨다.만약에 이parent가null이라면, 이 ClassLoader의parent는bootstrapclassloader입니다. 이parent가 무슨 소용이 있습니까?
우리는 이러한 상황을 고려할 수 있다. 만약에 우리가 클라이언트 Def ClassLoader를 사용자 정의했다고 가정하면, 우리는 이 사용자 정의 ClassLoader를 사용하여 자바를 불러옵니다.lang. String, 그럼 여기 String은 이 ClassLoader에 불러올까요?사실 자바.lang. String 클래스는 이 Client Def ClassLoader에 로드되는 것이 아니라 bootstrap classloader에 로드됩니다. 왜 이러십니까?실제로 이것이 양친 의뢰 모델의 원인이다. 사용자 정의 ClassLoader가 클래스를 불러오기 전에 아버지 ClassLoader에게 먼저 불러오기를 의뢰하기 때문이다. 아버지 ClassLoader가 불러오기에 성공하지 못하면 스스로 불러올 수 있기 때문이다. 위의 예에서java 때문이다.lang. String은 java 핵심 API의 한 종류에 속하기 때문에 ClientDefClassLoader를 사용하여 로드할 때 이 ClassLoader는 아버지인 ClassLoader에게 먼저 로드를 의뢰합니다. 위에서 말했듯이 ClassLoader의 parent가null일 때 ClassLoader의 parent는 bootstrap classloader이기 때문에 ClassLoader의 맨 윗부분은 bootstrap classloader이기 때문에 최종적으로 bootstrap classloader에 의뢰할 때bootstrap classloader는 String의 클래스로 돌아갑니다.
ClassLoader의 소스 코드를 살펴보겠습니다.

 protected synchronized Class loadClass(String name, boolean resolve) 
  throws ClassNotFoundException 
    { 
  //  name class  
  Class c = findLoadedClass(name); 
  if (c == null) { 
    try { 
    if (parent != null) { 
      // parent null, parent loadClass  
   = parent.loadClass(name, false); 
    } else { 
      //parent null, BootstrapClassLoader  
      c = findBootstrapClass0(name); 
    } 
    } catch (ClassNotFoundException e) { 
      // , findClass        
      c = findClass(name); 
    } 
  } 
  if (resolve) { 
    resolveClass(c); 
  } 
  return c; 
    } 
상기 코드에서 우리는 하나의 클래스가 불러오는 대략적인 과정이 이전에 내가 제시한 예와 같다는 것을 알 수 있다. 그러나 우리가 사용자 정의 클래스를 실현하려면findClass 방법만 실현하면 된다.
왜 이런 양친 위탁 모델을 사용해야 합니까?
첫 번째 이유는 중복 불러오는 것을 피할 수 있기 때문이다. 아버지가 이 종류를 불러왔을 때 하위 ClassLoader를 다시 불러올 필요가 없기 때문이다.
두 번째 이유는 안전 요소를 고려하여 생각해 보자. 만약에 이런 의뢰 모델을 사용하지 않는다면 우리는 언제든지 사용자 정의 String을 사용하여 자바 핵심api에서 정의한 유형을 동적으로 대체할 수 있다. 그러면 매우 큰 안전 위험이 존재하고 양친이 의뢰하는 방식은 이런 상황을 피할 수 있다. 왜냐하면 String은 이미 시작할 때 불러왔기 때문이다.따라서 사용자 정의 클래스는 사용자 정의 ClassLoader를 불러올 수 없습니다.
위에서 ClassLoader의 불러오는 메커니즘에 대해 대략적인 소개를 했습니다. 다음은 여기서 ClassLoader와 관련된 또 다른 클래스를 설명해야 합니다. 그것이 바로 Class 클래스입니다. 모든 ClassLoader에 불러오는 class 파일은 최종적으로 Class 클래스의 실례로 프로그래머에게 인용됩니다. 우리는 Class 클래스를 일반 클래스의 한 템플릿으로 간주할 수 있습니다. JVM은 이 템플릿에 따라 대응하는 실례를 생성하고 최종적으로 프로그래머가 사용할 수 있습니다.
Class 클래스에 정적 방법인 forName이 있는 것을 보았습니다. 이 방법은ClassLoader의loadClass 방법의 목적과 마찬가지로 모두class를 불러오는 데 사용되지만 두 가지 작용에 있어서는 차이가 있습니다.
Class loadClass(String name)
Class loadClass(String name, boolean resolve)
우리는 위의 두 가지 방법이 두 번째 방법의 두 번째 매개 변수는 불러오는 클래스를 설정할 때 이 클래스를 연결할지 여부를 설정하는 데 사용되며,true는 연결됩니다. 그렇지 않으면 연결되지 않습니다.
연결에 대해 말하자면 JVM이 클래스를 불러올 때 세 가지 절차를 거쳐야 한다. 불러오기, 연결, 초기화이다.불러오는 것은 상응하는 class 파일을 찾아서 JVM을 읽는 것입니다. 초기화는 말할 것도 없고 가장 중요한 것은 연결입니다.
연결은 3단계로 나뉜다. 첫 번째 단계는class가 규격에 부합되는지 검증하는 것이다. 두 번째 단계는 준비이다. 클래스 변수에 메모리를 분배하는 동시에 기본 초기값을 설정하는 것이다. 세 번째 단계는 해석이다. 이 단계는 선택할 수 있는 것이다. 위의loadClass 방법의 두 번째 파라미터에 따라 해석이 필요한지 판정하는 것이다. 이른바 해석은 이라는 책의 정의에 따라 클래스의 기호 인용에 따라 해당하는 실체를 찾는 것이다.다시 기호 인용을 직접 인용하는 과정으로 바꾸다.좀 심오하죠, 허허, 여기서는 설명이 많지 않아요. 구체적으로 알고 싶으면'JVM에 깊이 들어가세요'를 뒤져보세요. 허허, 이렇게 한 걸음 더 설명하면 언제 설명이 끝날지 몰라요.
우리는 다시 그 두 개의 매개 변수의loadClass 방법을 살펴보자. JAVA API 문서에서 이 방법의 정의는protected이다. 즉, 이 방법은 보호된 것이다. 사용자가 진정으로 사용해야 할 방법은 하나의 매개 변수의loadclass 방법은 실제적으로 두 개의 매개 변수를 호출하는 방법이고 두 번째 매개 변수는 기본적으로false이다.따라서loadClass를 통해 불러오는 클래스가 실제로 불러올 때 이 클래스에 대해 설명하지 않기 때문에 이 클래스를 초기화하지 않는다는 것을 알 수 있다.반면 Class 클래스의 forName 방법은 반대로 forName을 사용하여 불러올 때 Class를 해석하고 초기화합니다. forName도 다른 버전의 방법이 있습니다. 초기화 여부와 ClassLoader를 설정할 수 있습니다. 여기서 더 이상 언급하지 않겠습니다.
위의 두 가지 로드 방식에 대한 설명이 충분한지 모르겠습니다. 예를 들어 JDBC DRIVER의 로드, 예를 들어 우리는 JDBC 드라이브를 로드할 때 ClassLoader의loadClass 방법이 아니라 forName을 사용합니까?JDBC 드라이브는 DriverManager를 통해 DriverManager에 등록해야 하며, 드라이버 클래스가 초기화되지 않으면 DriverManager에 등록할 수 없기 때문에loadClass가 아닌 forName을 사용해야 한다는 것을 알고 있습니다.
ClassLoader를 통해 우리는 클래스 마운터를 사용자 정의하고 자신이 필요로 하는 마운트 방식을 사용자 정의할 수 있다. 예를 들어 네트워크에서 마운트하고 다른 형식의 파일에서 마운트하는 등이다. 사실 ClassLoader는 아직 언급하지 않은 부분이 많다. 예를 들어 ClassLoader 내부의 일부 실현 등이다.
이 글을 통해 편집자는 여러분들이 ClassLoader 메커니즘에 대해 이해해 주시기를 바랍니다. 지지해 주셔서 감사합니다!

좋은 웹페이지 즐겨찾기