Java 개발을 수행 할 때 클래스 로더 메커니즘에 익숙 해야하는 기본 지식입니다. 이 기사는 Java Classloader 메커니즘을 간단히 요약합니다. 다른 JVM 구현이 다르기 때문에이 기사에 설명 된 내용은 핫스팟 JVM으로 제한됩니다.
이 기사는 ClassLoader의 네 가지 측면, JDK가 제공하는 학부모 대표 모델, 클래스 로더를 사용자 정의하는 방법 및 Java의 학부모 위임 메커니즘을 깨는 시나리오로 시작합니다.
JDK 기본 클래스 로더
JDK는 기본적으로 다음 클래스 로더를 제공합니다
Bootstrp 로더
Bootstrp 로더는 C ++ 언어로 작성되었습니다. Java Virtual Machine이 시작된 후 초기화됩니다. 주로 %java_home %/jre/lib, -xbootclasspath 매개 변수 및 %java_home %/jre/classe의 클래스로 지정된 경로를로드하는 책임이 있습니다.
ExtClassLoader
Bootstrp 로더는 ExtClassLoader를로드하고 ExtClassLoader의 상위 로더를 Bootstrp 로더로 설정합니다 .extClassLoader는 Java, 특히 Sun.Launcher $ extClassLoader로 작성됩니다. ExtClassLoader는 주로 %java_home %/jre/lib/ext,이 경로의 모든 클래스 디렉토리 및 Java.ext.dirs 시스템 변수에 의해 지정된 경로의 클래스 라이브러리를로드합니다.
AppClassloader
Bootstrp 로더가 ExtClassLoader를로드하면 AppClassLoader가로드되고 AppClassLoader의 상위 로더가 ExtClassLoader로 지정됩니다. AppClassLoader는 Java로 작성되었습니다. 구현 클래스는 Sun.misc.launcher $ appclassloader입니다. 또한 클래스 로더에 GetSystemClassLoader 메소드가 있음을 알고 있습니다. 이 메소드는 AppClassLoader를 반환합니다. AppClassLoader는 주로 ClassPath에서 지정된 위치에 클래스 또는 JAR 문서를로드 할 책임이 있습니다. 또한 Java 프로그램의 기본 클래스 로더이기도합니다.
부모 대표 모델
Java의 클래스 로더로드는 부모 대의원 메커니즘을 채택합니다. 부모 대의원 메커니즘을 사용하여 클래스를로드 할 때 다음 단계가 채택됩니다.
현재 ClassLoader는 먼저이 클래스가 이미로드 된 클래스에서로드되었는지 확인합니다. 로드 된 경우 원래 클래스를 직접 반환합니다.
각 클래스 로더에는 자체로드 캐시가 있습니다. 클래스가로드되면 캐시에 넣고 다음에로드 될 때 직접 반환 할 수 있습니다.
클래스 로더의 캐시를 찾을 수 없으면 부모 클래스 로더가로드되도록 위임됩니다. 부모 클래스 로더는 동일한 전략을 채택합니다. 먼저, 자체 캐시를 확인한 다음 부모 클래스의 상위 클래스를 부트 스트프 클래스 로더로 모든로드하도록 위임하십시오.
모든 상위 클래스 로더가로드되지 않으면 현재 클래스 로더에 의해로드되어 다음에로드 요청이있을 때 직접 반환 할 수 있도록 자체 캐시에 넣습니다.
이것에 대해 말하면, Java가 왜 그러한 대표단 메커니즘을 채택합니까? 이 문제를 이해하기 위해 클래스 로더에 대한 또 다른 개념 "네임 스페이스"를 소개합니다. 즉, 특정 클래스를 결정하려면 클래스의 자격을 갖춘 이름이 필요 하고이 클래스 클래스 로더를로드하여 공동으로 결정합니다. 즉, 두 클래스의 완전히 자격을 갖춘 이름이 동일하더라도 다른 클래스 로더 가이 클래스를로드하기 때문에 JVM의 다른 클래스입니다. 네임 스페이스를 이해 한 후 대의원 모델을 살펴 보겠습니다. 대의원 모델을 채택한 후 다른 클래스 로더의 대화식 기능이 증가합니다. 예를 들어, 위에서 언급 한 바와 같이, Hashmap, LinkedList 등과 같은 JDK Binsheng이 제공 한 클래스 라이브러리는 Bootstrp 클래스 로더에 의해로드 된 후 프로그램에 몇 개의 클래스 로더 수에 관계 없이이 클래스가 실제로 공유 될 수 있으므로 동일한 이름의 다른 클래스 로딩으로 인해 발생하는 클래스 로더로 인한 혼란을 피할 수 있습니다.
클래스 로더를 사용자 정의하는 방법
위에서 언급 한 기본적으로 제공된 클래스 로더 외에도 Java는 응용 프로그램이 클래스 로더를 사용자 정의 할 수 있도록합니다. 클래스 로더를 사용자 정의하려면 java.lang.classloader를 상속하여 구현해야합니다. 다음으로 클래스 로더를 사용자 정의 할 때주의를 기울여야하는 몇 가지 중요한 방법을 살펴 보겠습니다.
1. 클래스 방법
로드 클래스 메소드는 선언합니다
public class <?> loadclass (문자열 이름)는 classNotFoundException을 던집니다
위는로드 클래스 방법의 프로토 타입 선언입니다. 위에서 언급 한 부모 대의원 메커니즘의 구현은 실제로이 방법에서 구현됩니다. 이 방법의 코드를 살펴보고 그것이 부모 대의원을 어떻게 구현하는지 알아 보겠습니다.
로드 클래스 메소드 구현
public class <?> loadclass (문자열 이름)는 classNotFoundException {return loadclass (name, false);} 던지기위에서 Loadclass 메소드가 loadcclass (이름, false) 메소드를 호출하는 것을 볼 수 있으므로 다른 loadclass 메소드의 구현을 살펴 보겠습니다.
클래스 loadclass (문자열 이름, 부울 결의)
보호 된 동기화 된 클래스 (문자열 이름, 부울 resolve)는 classNotFoundException {// 첫 번째, 클래스가 이미로드되었는지 확인 C = findloadedClass (name); // 클래스가 (c == null) {if (parent! = null) {c = parent.load Class (over)가 아니에요 로더가 지정되고, 상위 로더가로드되도록 위임됩니다. } else {c = findbootstrapclass0 (name); // 부모 클래스 로더가 없으면 부트 스트랩 로더를로드하도록 위임}} catch (classNotFoundException e) {// 아직 찾을 수없는 경우, findclass를 호출하여 클래스를 찾으십시오. c = findclass (name); // 부모 클래스로드가로드되지 않으면 자체 FindClass를 통해로드됩니다. }} if (resolve) {resolveClass (c);} return c;}위의 코드에서는 Loadclass의 상위 대의원 메커니즘이 어떻게 작동하는지 명확하게 확인하기 위해 의견을 추가했습니다. 여기서 주목해야 할 한 가지는 공개 클래스 <?>로드 클래스 (문자열 이름)가 ClassNotFoundException이 최종적으로 표시되지 않으므로이 메소드를 무시할 수 있음을 의미합니다. 즉, 부모 위임 메커니즘이 깨질 수 있음을 의미합니다. 또한 위의 FindClass 메소드가 있음을 알았습니다. 다음 으로이 방법이 나쁜 방법에 대해 이야기 해 봅시다.
2. indclass
우리는 java.lang.classloader의 소스 코드를 확인하고 FindClass의 구현은 다음과 같습니다.
보호 클래스 <?> findClass (문자열 이름) 던지기 classNotFoundException {새 ClassNotFoundException (name);}이 메소드의 기본 구현은 직접 예외를 제외하는 것임을 알 수 있지만 실제로이 방법은 응용 프로그램에 맡겨져 재정의합니다. 특정 구현은 구현 로직에 따라 다릅니다. 디스크에서 읽거나 네트워크에서 클래스 파일의 바이트 스트림을 얻을 수 있습니다. 클래스 바이너리를 얻은 후에는 추가 로딩을 위해 정의로 넘겨 줄 수 있습니다. 나중에 정의를 설명해 봅시다. 자, 위의 분석을 통해 다음과 같은 결론을 도출 할 수 있습니다.
우리가 자신의 클래스 로더를 작성할 때, 부모 대의원 메커니즘을 따르고 싶다면 FindClass를 무시하면됩니다.
3. 정의
먼저 정의의 소스 코드를 살펴 보겠습니다.
정의
보호 된 최종 클래스 <?> defineClass (문자열 이름, 바이트 [] b, int off, int len)는 classformaterror {return defuleclass (name, b, off, len, null);} 던지기위의 코드 에서이 메소드가 최종으로 정의되어 있음을 알 수 있습니다. 즉,이 메소드는 재정의 할 수 없습니다. 실제로 이것은 JVM이 우리에게 남겨진 유일한 항목입니다. 이 고유 한 항목을 통해 JVM은 클래스 파일이 Java Virtual Machine 사양에 지정된 클래스의 정의를 준수해야합니다. 이 방법은 마침내 기본 방법을 호출하여 실제 클래스의로드를 구현합니다.
자, 위의 설명을 통해 다음 질문에 대해 생각해 봅시다.
우리가 java.lang.string 클래스를 스스로 썼다면 JDK 자체라고하는 클래스를 대체 할 수 있습니까?
대답은 아니오입니다. 우리는 그것을 달성 할 수 없습니다. 왜? 부모 대의원 메커니즘 이이 문제를 해결한다는 많은 온라인 설명이 보이지만 실제로는 정확하지 않습니다. 상위 대의원 메커니즘을 깨뜨릴 수 있으므로 java.lang.string 클래스를로드하기 위해 클래스 로더를 작성할 수 있지만 성공적으로로드되지 않을 것입니다. 특히 Java.*로 시작하는 클래스의 경우 JVM의 구현으로 Bootstrp에 의해로드되어야합니다.
"부모 위임 메커니즘"을 따르지 않는 시나리오
상기는 부모 대표 메커니즘이 주로 다른 클래스 로더간에로드 된 클래스의 상호 작용 문제를 실현하기위한 것이라고 언급했다. 모든 사람이 공유하는 클래스는로드하기 위해 부모 로더로 넘겨 지지만 실제로 부모 클래스 로더가로드 한 클래스가 하위 로더가로드 한 클래스를 사용해야하는 Java에는 실제로 상황이 있습니다. 이 상황의 발생에 대해 이야기합시다.
JDBC, JNDI 등과 같은 SPI 라이브러리를 사용하는 Java에는 SPI (ServiceProviderInterface) 표준이 있습니다. 우리는 JDBC가 제 3자가 제공 한 드라이버를 요구하고 운전자의 JAR 패키지는 응용 프로그램 자체의 클래스 경로에 배치된다는 것을 알고 있습니다. JDBC 자체의 API는 JDK가 제공하는 JDK의 일부이며 Bootstrp에 의해로드되었습니다. 그렇다면 타사 제조업체가 제공하는 구현 클래스를 어떻게로드합니까? Java는 스레드 컨텍스트 클래스 로딩의 개념을 소개합니다. 스레드 클래스 로더는 기본적으로 상위 스레드에서 상속됩니다. 지정되지 않은 경우 기본값은 시스템 클래스 로더 (AppClassLoader)입니다. 이런 식으로 타사 드라이버가로드되면 스레드의 컨텍스트 클래스 로더를 통해로드 할 수 있습니다.
또한보다 유연한 클래스 로더 OSGI와 일부 JavaAppServers를 구현하기 위해 부모 대의원 메커니즘을 중단합니다.
요약
위는 Java Classloader 메커니즘의 사용 및 사용에 대한 코드 분석에 대한이 기사의 모든 내용입니다. 모든 사람에게 도움이되기를 바랍니다. 관심있는 친구는이 사이트의 다른 관련 주제를 계속 참조 할 수 있습니다. 단점이 있으면 메시지를 남겨 두십시오. 이 사이트를 지원해 주신 친구들에게 감사드립니다!