머리말
Java 프로젝트가 시작될 때 JVM은 주요 메소드를 찾아서 객체 사이의 통화에 따라 참조 된 JAR 패키지에 클래스 파일과 클래스 파일을로드한다는 것을 알아야합니다 (단계는로드, 확인, 준비, 구문 분석, 초기화, 사용 및 언로드로 나뉩니다. 메소드 영역은 클래스의 런타임 데이터 구조 (정적 변수, 정적 메소드, 일정한 풀, 클래스 구조 등)를 저장하기 위해 메모리를 열고 동시에 해당 클래스 객체가 메소드 영역의 해당 클래스 런타임 데이터 구조를 가리키기 위해 힙에 생성됩니다.
가장 간단한 문장으로 요약하면 클래스로드 프로세스는 JVM이 필요한 클래스 파일의 경로를 기반으로 IO 스트림을 통해 클래스 바이트 코드 파일을 읽고 일련의 구문 분석 및 초기화 단계를 통해 메모리에 주입한다는 것입니다. Java의 클래스 로더에는 Bootstrapclassloader (상단 계층), ExtclassLoader, AppClassLoader 및 사용자 정의 클래스 로더 (하단 계층)가 포함됩니다. 다른 유형의 JAR 패키지 (또는 클래스 파일)의 경우 JVM에는 다른 유형의 클래스 로더가 있습니다.
해당 관계는 다음과 같습니다.
부트 스트랩 클래스 로더는 JVM 실행에 필요한 클래스를로드하는 데 사용됩니다.
java_home/jre/lib/resources.jar : java_home/jre/lib/rt.jar : java_home/jre/lib/sunrasign.jar : java_home/jre/lib/jsse.jar : java_home/jre/lib/jce.jar : java_home/charsets. java_home/jre/lib/jfr.jar : java_home/jre/lib/클래스
ExtClassLoader는 Extension 클래스를로드하는 데 사용됩니다.
../java/extensions : ../java_home/jre/lib/ext : ../library/java/extensions :/network/library/java/extensions : ../system/library/java/extensions : ../lib/java
AppClassLoader는 ClassPath에서 생성 된 클래스와 프로젝트의 JAR 패키지에 참조 된 클래스를로드하는 데 사용됩니다.
전체 클래스 로딩은 부모 대표라는 메커니즘을 통해로드됩니다.
예를 들어, 클래스는 가장 낮은 레벨 로더 (사용자 정의 클래스 로더)에 의해로드됩니다. 이 로더는 먼저 로딩을 위해 이전 레벨 로더 (AppClassLoader)를 호출하며 AppClassLoader는 부트 스트랩 클래스 로더가로드 될 때까지로드하기 위해 상단 레벨 (ExtClassLoader)으로 계속 전달됩니다. BootstrapClassLoader로로드 된 클래스 경로 가이 클래스를 찾을 수없는 경우로드를 위해 다음 레이어의 로더 (ExtClassLoader)로 전달됩니다. 이 클래스를 찾을 수없는 경우로드를 위해 다음 레이어 (AppClassLoader)로 계속 전달됩니다. 따라서 사용자 정의 클래스 로더 가이 클래스를 찾을 수없는 경우 프로그램에 ClassNotFoundError를 던집니다.
전체 로딩 프로세스는 다음과 같이 표시됩니다.
(이미지는 다음과 같습니다. https://www.cnblogs.com/xing901022/p/4574961.html)
클래스로드 소스의 소스 코드 추적은 다음과 같습니다 (소스 코드는 여기에서 적절하게 단순화되었습니다). 독자는 소스 코드를 클릭하여 볼 수 있습니다.
패키지 java.lang.classloader; import ... import ...... 보호 된 클래스 <?>로드 클래스 (문자열 이름, 부울 resolve)는 classNotFoundException {synchronized (getClassLoadingLock (name)) {// 먼저이 클래스가로드되었는지 여부를 찾으십시오. ! ! class <?> c = findloadedClass (이름); if (c == null) {long t0 = system.nanoTime (); try {if (parent! = null) {// 이전 레이어 로더로드를 먼저하자 c = parent.loadclass (이름, false); } else {c = findBootStrapClassorNull (이름); }} catch (classNotFoundException e) {// 클래스를 찾을 수없는 경우 classnotfoundException // null 부모 클래스 로더에서 //를 찾을 수없는 경우} if (c == null) {// calendar이 로더가 구현 한 fingclass (findclass); }} if (resolve) {resolveClass (c); } 반환 c; }}소스 코드에서 상위 대의원 메커니즘의 프로세스에 완전히 감사 할 수 있으며 코드의 가장 중요한 세 문장이 표시되었습니다.
사용자가 사용자 정의 로더가 필요하고 지정된 경로의 클래스 파일을로드하는 경우 클래스 로더를 상속하고 FindClass (String Name) 메소드를 구현해야합니다. 예를 들어 :
package com.linuxidc.utils; import java.io.bytearrayoutputStream; import java.io.fileInputStream; import java.io.ioexception; import java.io.inputStream; public class serviceclassloader classloader {private string classpath; 공공 서비스 클래스 로더 (String ClassPath) {this.classpath = classPath; } /*** 부모 클래스의 FindClass 메소드를 다시 작성하십시오. 부모 클래스의로드 클래스는이 메소드를 호출합니다 */ @override protected class <?> findclass (문자열 이름)는 classNotFoundException {class <?> c = null을 던집니다. 바이트 [] classData = getClassData (이름); if (classData! = null) {c = defuleClass (이름, classData, 0, classData.length); } else {throw new classNotFoundException (); } 반환 c; } // IO 스트림을 통해 클래스 파일을 읽고 바이트 배열 개인 바이트로 변환하십시오 [] getClassData (문자열 이름) {String Path = ClassPath + "/" + name.replace ( '.', '/') + ".class"; inputStream istream = null; BYTEARRAYOUTPUTSTREAM BYTEARRAYOUTPUTSTREAM = NEW BYTEARRAYOUTPUTSTREAM (); try {istream = new FileInputStream (Path); 바이트 [] 버퍼 = 새로운 바이트 [1024]; int temp = 0; while ((temp = istream.read (buffer))! = -1) {bytearrayoutputStream.write (buffer, 0, temp); } if (bytearRayoutputStream! = null) {return bytearRayoutputStream.tobytearRay (); }} catch (예외 e) {e.printstacktrace (); } 마침내 {try {if (istream! = null) {istream.close (); }} catch (ioexception e) {e.printstacktrace (); } try {if (bytearRayoutputStream! = null) {bytearRayOutputStream.close (); }} catch (ioexception e) {e.printstacktrace (); }} return null; }}클래스 로더 사용 코드는 다음과 같습니다.
ServiceClassLoader ServiceClassLoader = 새로운 ServiceClassLoader ( "C :/MyClass"); CZLASS <?> C = ServiceClassLoader.loadClass ( "com.linuxidc.service.myclass");
동일한 ServiceClassLoader 객체를 사용하여 동일한 클래스 파일을 여러 번로드하면 각로드 후 클래스 객체가 동일합니다! 그러나 새로운 다른 사용자 정의 클래스 로더가 동일한 클래스 파일을로드하면 매번 다른 클래스 객체가 반환됩니다.
참고 : 로드하려는 클래스 파일은 ClassPath 디렉토리 및 모든 하위 디렉토리에 배치 할 수 없습니다. 그렇지 않으면 AppClassLoader가 먼저로드합니다 (클래스로드가 상위 대의원 메커니즘을 채택하고 AppClassLoader가 클래스 경로 아래에 모든 클래스 파일을로드 할 수 있기 때문입니다). 매번 동일한 AppClassLoader가로드되므로 클래스 캐싱 문제가 발생합니다.
이것은 JVM 클래스가로드 될 때 반사를 직접 사용하는 문제를 해결합니다.
요약
위는이 기사의 전체 내용입니다. 이 기사의 내용에 모든 사람의 연구 나 작업에 대한 특정 참조 가치가 있기를 바랍니다. 궁금한 점이 있으면 의사 소통을 위해 메시지를 남길 수 있습니다. Wulin.com을 지원 해주셔서 감사합니다.