1부. 프롬프트 이 기사를 읽어야 합니까?
Java 클래스 로더는 Java 시스템 작동에 매우 중요하지만 종종 무시됩니다. Java 클래스 로더는 런타임 시 클래스를 찾아서 로드하여 로드합니다. 사용자 정의 클래스 로더는 클래스가 로드되는 방식을 완전히 변경하여 원하는 방식으로 Java 가상 머신을 개인화할 수 있습니다. 이 기사에서는 Java 클래스 로더를 간략하게 소개한 다음 사용자 정의 클래스 로더를 구성하는 예제를 통해 이를 설명합니다. 이 클래스 로더는 클래스를 로드하기 전에 자동으로 코드를 컴파일합니다. 클래스 로더가 실제로 수행하는 작업과 자신만의 클래스 로더를 만드는 방법을 배우게 됩니다. 몇 가지 기본 Java 지식이 있고 명령줄 Java 프로그램을 생성, 컴파일 및 실행하는 방법과 Java 클래스 파일의 몇 가지 기본 개념을 알고 있으면 이 기사의 내용을 이해할 수 있습니다. 이 기사를 읽은 후에는 다음을 수행할 수 있어야 합니다.
* 자바 가상 머신의 기능 확장
* 사용자 정의 클래스 로더 만들기
* 사용자 정의 클래스 로더를 애플리케이션에 통합하는 방법
* 클래스 로더를 Java 2와 호환되도록 수정하세요.
파트 2. 소개 클래스 로더란 무엇입니까?
Java와 다른 언어의 차이점은 Java는 JVM(Java Virtual Machine)에서 실행된다는 점입니다. 이는 컴파일된 코드가 특정 시스템에서 실행되는 형식이 아닌 플랫폼 독립적인 형식으로 저장된다는 의미입니다. 이 형식은 기존의 실행 가능한 코드 형식과 많은 중요한 차이점이 있습니다. 특히 C 또는 C++ 프로그램과 달리 Java 프로그램은 독립적인 실행 파일이 아니지만 각 클래스 파일은 Java 클래스에 해당하는 여러 개별 클래스 파일로 구성됩니다. 또한 이러한 클래스 파일은 즉시 메모리에 로드되지 않고 프로그램에서 필요할 때 로드됩니다. 클래스 로더는 Java 가상 머신에서 클래스를 메모리에 로드하는 데 사용되는 도구입니다. 또한 Java 클래스 로더도 Java로 구현됩니다. 이렇게 하면 Java 가상 머신에 대한 심층적인 이해 없이도 자신만의 클래스 로더를 쉽게 만들 수 있습니다.
클래스 로더를 만드는 이유는 무엇입니까?
이제 Java Virtual Gold에는 클래스 로더가 이미 있으므로 다른 클래스 로더를 직접 만들어야 합니까? 좋은 질문입니다. 기본 클래스 로더는 로컬 시스템에서 클래스를 로드하는 방법만 알고 있습니다. 프로그램이 완전히 기본적으로 컴파일되면 기본 클래스 로더가 일반적으로 잘 작동합니다. 그러나 Java의 가장 흥미로운 점 중 하나는 로컬이 아닌 네트워크에서 클래스를 로드하는 것이 얼마나 쉬운지입니다.
예를 들어 브라우저는 사용자 정의 클래스 로더를 통해 클래스를 로드할 수 있습니다. 클래스를 로드하는 방법도 다양합니다. Java의 가장 흥미로운 점 중 하나는 로컬이나 네트워크에서 간단하게 사용자 정의할 수 있다는 것입니다.
* 신뢰할 수 없는 코드를 실행하기 전에 자동으로 디지털 서명을 확인합니다.
* 사용자가 제공한 비밀번호를 기반으로 코드를 해독합니다.
* 사용자 요구에 따라 클래스를 동적으로 생성합니다. JDK(Java Software Development Kit) 애플릿뷰어(소형 애플리케이션 브라우저) 또는 기타를 사용한 경우 사용자 정의 클래스 로더의 예는 관심 있는 모든 것을 애플리케이션에 쉽게 통합할 수 있습니다.
Java 임베디드 브라우저의 경우 이미 사용자 정의 클래스 로더를 사용하고 있습니다. Sun이 처음 Java 언어를 출시했을 때 가장 흥미로웠던 것 중 하나는 Java가 원격 웹 사이트에서 다운로드한 코드를 어떻게 실행하는지 관찰하는 것이었습니다. HTTP를 통해 원격 사이트에서 실행
P 연결에 의해 전송된 바이트코드가 조금 이상해 보입니다. 이는 Java에 사용자 정의 클래스 로더를 설치할 수 있는 기능이 있기 때문에 작동합니다. 애플릿 브라우저에는 클래스 로더가 포함되어 있습니다. 이 클래스 로더는 로컬에서 Java 클래스를 찾는 대신 원격 서버에 액세스하여 HTTP를 통해 원본 바이트코드 파일을 로드한 다음 이를 Java 가상 머신에서 Java 클래스로 변환합니다. 물론 클래스 로더는 다른 많은 작업도 수행합니다. 즉, 안전하지 않은 Java 클래스를 차단하고 서로 다른 페이지에 있는 서로 다른 애플릿이 서로 간섭하지 않도록 합니다. Luke Gorrie가 작성한 패키지인 Echidna는 여러 Java 애플리케이션을 Java 가상 머신에서 안전하게 실행할 수 있는 개방형 Java 소프트웨어 패키지입니다. 이는 사용자 정의 클래스 로더를 사용하여 각 애플리케이션에 클래스 파일의 사본을 제공함으로써 애플리케이션 간의 간섭을 방지합니다.
클래스 로더 예제 이제 클래스 로더가 작동하는 방식과 자체 클래스 로더를 정의하는 방법을 알았으므로 CompilingClassLoader(CCL)라는 사용자 정의 클래스 로더를 생성합니다. CCL은 우리를 위해 컴파일 작업을 수행하므로 우리가 직접 수동으로 컴파일할 필요가 없습니다. 이는 기본적으로 런타임 환경에 구축되는 "make" 프로그램을 갖는 것과 동일합니다.
참고: 다음 단계로 진행하기 전에 몇 가지 관련 개념을 이해해야 합니다.
JDK 버전 1.2(Java 2 플랫폼이라고 함)에서는 시스템이 크게 개선되었습니다. 이 기사는 JDK 1.0 및 1.1에서 작성되었지만 모든 것이 이후 버전에서도 작동합니다. ClassLoader도 Java2에서 개선되었습니다.
자세한 소개는 5부에서 다룬다.
파트 3. ClassLoader 구조 개요 클래스 로더의 기본 목적은 Java 클래스에 대한 요청을 처리하는 것입니다. Java Virtual Machine은 클래스가 필요할 때 클래스 이름을 클래스 로더에 제공하고 클래스 로더는 해당 클래스 인스턴스를 반환하려고 시도합니다. 사용자 정의 클래스 로더는 여러 단계에서 해당 메서드를 재정의하여 생성할 수 있습니다. 다음으로 클래스 로더의 주요 메소드 중 일부에 대해 알아 보겠습니다. 이러한 메서드의 기능과 클래스 파일을 로드할 때 작동하는 방식을 이해하게 됩니다. 또한 사용자 정의 클래스 로더를 생성할 때 작성해야 하는 코드가 무엇인지도 알 수 있습니다. 다음 부분에서는 이 지식과 사용자 정의 CompilingCl을 활용하게 됩니다.
assLoader는 함께 작동합니다.
메소드 loadClass
ClassLoader.loadClass()는 ClassLoader의 진입점입니다. 메소드 서명은 다음과 같습니다.
클래스 loadClass(문자열 이름, 부울 해석);
매개변수 이름은 Foo 또는 java.lang.Object와 같이 JVM(Java Virtual Machine)에 필요한 클래스의 전체 이름(패키지 이름 포함)을 지정합니다.
해결 매개변수는 클래스를 해결해야 하는지 여부를 지정합니다. 클래스의 해결이 완전히 실행 준비가 된 것으로 이해할 수 있습니다. 일반적으로 구문 분석은 필요하지 않습니다. Java 가상 머신이 이 클래스가 존재하는지 여부만 알고 싶거나 상위 클래스를 알고 싶다면 구문 분석이 전혀 필요하지 않습니다. Java 1.1 및 이전 버전에서 클래스 로더를 사용자 정의하려는 경우 loadClass 메소드는 서브클래스에서 대체해야 하는 유일한 메소드입니다.
(ClassLoader는 Java1.2에서 변경되었으며 findClass() 메소드를 제공했습니다).
메소드 정의클래스
DefineClass는 ClassLoader의 매우 신비한 메소드입니다. 이 메소드는 바이트 배열에서 클래스 인스턴스를 빌드합니다. 데이터가 포함된 이 원시 바이트 배열은 파일 시스템이나 네트워크에서 나올 수 있습니다. DefineClass는 JVM(Java Virtual Machine)의 복잡성, 미스터리 및 플랫폼 종속성을 보여줍니다. 이는 바이트코드를 해석하여 이를 런타임 데이터 구조로 변환하고 유효성을 검사하는 등의 작업을 수행합니다. 하지만 걱정하지 마세요. 이 작업을 수행할 필요는 없습니다. 실제로는 전혀 무시할 수 없습니다.
메서드가 final 키워드에 의해 수정되기 때문입니다.
MethodfindSystemClass
findSystemClass 메소드는 로컬 시스템에서 파일을 로드합니다. 로컬 시스템에서 클래스 파일을 찾고, 발견되면 호출합니다.
DefineClass는 원래 바이트 배열을 클래스 객체로 변환합니다. 이는 Java 애플리케이션을 실행할 때 JVM(Java Virtual Machine)이 클래스를 로드하는 기본 메커니즘입니다. 사용자 정의 클래스 로더의 경우 로드에 실패한 후에 findSystemClass만 사용하면 됩니다. 이유는 간단합니다. 클래스 로더는 클래스 로딩의 특정 단계를 수행하지만 모든 클래스를 수행하는 것은 아닙니다. 예를 들어,
클래스 로더가 원격 사이트에서 일부 클래스를 로드하더라도 로컬 시스템에서 로드해야 하는 기본 클래스가 여전히 많이 있습니다.
이러한 클래스는 우리와 관련이 없으므로 Java 가상 머신이 기본 방식인 로컬 시스템에서 로드하도록 합니다. 이것이 findSystemClass가 하는 일입니다. 전체 과정은 대략 다음과 같습니다.
* Java 가상 머신은 클래스를 로드하기 위해 사용자 정의 클래스 로더를 요청합니다.
* 원격 사이트에 로드해야 할 클래스가 있는지 확인합니다.
* 있다면 이 수업을 듣습니다.
* 그렇지 않은 경우 이 클래스가 기본 클래스 라이브러리에 있다고 생각하고 findSystemClass를 호출하여 파일 시스템에서 로드합니다.
대부분의 사용자 정의 클래스 로더에서는 원격에서 조회하는 시간을 절약하기 위해 먼저 findSystemClass를 호출해야 합니다.
실제로 다음 섹션에서 살펴보겠지만 Java 가상 머신은 코드가 자동으로 컴파일되었다고 확신할 때만 로컬 파일 시스템에서 클래스를 로드할 수 있습니다.
메서드 해결Class
위에서 언급했듯이 클래스 기록은 부분 로딩(파싱 없음)과 완전 로딩(파싱 포함)으로 나눌 수 있습니다. 사용자 정의 클래스 로더를 생성할 때,solveClass를 호출해야 할 수도 있습니다.
MethodfindLoadedClass
findLoadedClass는 캐시를 구현합니다. 클래스를 로드하기 위해 loadClass가 필요한 경우 먼저 이 메서드를 호출하여 이미 로드된 클래스를 다시 로드하는 것을 방지하기 위해 클래스가 로드되었는지 확인할 수 있습니다. 이 메서드를 먼저 호출해야 합니다. 이러한 메서드가 어떻게 구성되어 있는지 살펴보겠습니다.
loadClass의 예제 구현은 다음 단계를 수행합니다. (클래스 파일을 얻기 위한 특정 기술을 지정하지 않습니다. 이는 네트워크, 압축 패키지 또는 동적으로 컴파일된 것일 수 있습니다. 어떤 경우에도 우리가 얻는 것은 원본 바이트코드 파일입니다.)
* 이 클래스가 로드되었는지 확인하려면 findLoadedClass를 호출하세요.
* 로드되지 않은 경우 어떻게든 원본 바이트 배열을 얻습니다.
* 배열을 구했다면, DefineClass를 호출하여 클래스 객체로 변환합니다.
* 원본 바이트 배열을 얻을 수 없는 경우 findSystemClass를 호출하여 로컬 파일 시스템에서 기록할 수 있는지 확인합니다.
*Resolve 매개변수가 true인 경우, ResolveClass를 호출하여 클래스 객체를 해결합니다.
* 클래스를 찾지 못한 경우 ClassNotFoundException을 발생시킵니다.
* 그렇지 않으면 이 클래스를 반환합니다.
이제 클래스 로더에 대한 실무 지식을 보다 포괄적으로 이해했으므로 사용자 정의 클래스 로더를 만들 수 있습니다. 다음 섹션에서는 CCL에 대해 설명하겠습니다.
4부. ClassLoader 컴파일하기
CCL은 클래스 로더의 기능을 보여줍니다. CCL의 목적은 코드를 자동으로 컴파일하고 업데이트할 수 있도록 하는 것입니다. 작동 방식은 다음과 같습니다.
* 클래스 요청이 있는 경우, 먼저 현재 디렉터리와 디스크의 하위 디렉터리에 해당 클래스 파일이 존재하는지 확인하세요.
* 클래스 파일은 없지만 소스코드 파일이 있는 경우 자바 컴파일러를 호출하여 클래스 파일을 컴파일하고 생성한다.
* 클래스 파일이 이미 존재하는 경우 해당 클래스 파일이 소스 코드 파일보다 오래된 것인지 확인하세요. 클래스 파일이 소스 코드 파일보다 오래된 경우 Java 컴파일러를 호출하여 클래스 파일을 다시 생성합니다.
* 컴파일이 실패하거나 다른 이유로 소스 파일에서 클래스 파일을 생성할 수 없는 경우 ClassNotFou 예외가 발생합니다.
ndException.
* 아직 이 클래스를 얻지 못한 경우, findSystemClass를 호출하여 찾을 수 있는지 확인하세요.
* 찾을 수 없으면 ClassNotFoundException을 발생시킵니다.
* 그렇지 않으면 이 클래스를 반환합니다.
Java 컴파일은 어떻게 구현됩니까?
더 진행하기 전에 Java 컴파일 프로세스를 이해해야 합니다. 일반적으로 Java 컴파일러는 지정된 클래스만 컴파일합니다. 또한 지정된 클래스에 필요한 경우 다른 관련 클래스도 컴파일합니다. CCL은 애플리케이션에서 컴파일하는 데 필요한 클래스를 하나씩 컴파일합니다. 그러나 일반적으로 말하면 컴파일러가 첫 번째 클래스를 컴파일한 후에는
CCL은 다른 필수 관련 클래스가 실제로 컴파일되었는지 확인합니다. 왜? Java 컴파일러는 우리가 했던 것과 유사한 규칙을 사용합니다. 즉, 클래스가 존재하지 않거나 소스 파일이 업데이트된 경우 클래스가 컴파일됩니다. Java 컴파일러는 기본적으로 CCL보다 한 단계 앞서 있으며 대부분의 작업은 Java 컴파일러에서 수행됩니다. CCL이 이러한 클래스를 컴파일하는 것 같습니다.
대부분의 경우, 메인 함수 클래스에서 컴파일러를 호출하고 있다는 것을 알게 될 것입니다. 그게 전부입니다. 간단한 호출이면 충분합니다. 그러나 이러한 클래스가 처음 나타날 때 컴파일되지 않는 특별한 경우가 있습니다. Class.forName 메소드를 사용하여 이름을 기반으로 클래스를 로드하는 경우 Java 컴파일러는 클래스가 필요한지 여부를 알 수 없습니다. 이 경우,
CCL이 컴파일러를 다시 호출하여 클래스를 컴파일하는 것을 발견했습니다. 섹션 6의 코드는 이 프로세스를 보여줍니다.
CompilationClassLoader 사용
CCL을 사용하려면 프로그램을 직접 실행할 수 없으며 다음과 같은 특별한 방법으로 실행해야 합니다.
% 자바 푸 arg1 arg2
우리는 다음과 같이 실행합니다:
% 자바 CCLRun Foo arg1 arg2
CCLRun은 CompilingClassLoader를 생성하고 이를 사용하여 기본 함수 클래스를 로드하는 특수 스텁 프로그램입니다. 이는 전체 프로그램이 CompilingClassLoader에 의해 로드되도록 보장합니다. CCLRun은 Ja를 활용합니다.
va 리플렉션 API는 기본 함수 클래스의 기본 함수를 호출하고 이 함수에 매개변수를 전달합니다. 자세한 내용은 6부의 소스 코드를 참조하세요.
전체 프로세스가 어떻게 작동하는지 보여주기 위해 예제를 실행해 보겠습니다.
메인 프로그램은 Bar 클래스의 인스턴스를 생성하는 Foo라는 클래스입니다. 이 Bar 인스턴스는 Baz 패키지에 존재하는 Baz 클래스의 인스턴스를 생성합니다. 이는 CCL이 하위 패키지에서 클래스를 로드하는 방법을 보여줍니다. Bar는 클래스 이름을 기반으로 Boo 클래스도 로드합니다.
, 이것도 CCL에 의해 수행됩니다. 모든 클래스가 로드되어 실행할 준비가 되었습니다. 이 프로그램을 실행하려면 6장의 소스 코드를 사용하십시오. CCLRun 및 CompilingClassLoader를 컴파일합니다. 다른 클래스(Foo, Bar, Baz,
nd Boo), 그렇지 않으면 CCL이 작동하지 않습니다.
% 자바 CCLRun Foo arg1 arg2
CCL: Foo.java 컴파일 중...
푸! 인수1 인수2
바! 인수1 인수2
바즈! 인수1 인수2
CCL: Boo.java 컴파일 중...
우우!
Foo.java에 대해 처음으로 컴파일러가 호출되고 Bar와 baz.Baz도 함께 컴파일됩니다. 그리고 부처럼
채널을 로드해야 할 때 CCL은 컴파일러를 다시 호출하여 채널을 컴파일합니다.
5부. Java 2의 클래스 로더 개선 개요 Java 1.2 이상 버전에서는 클래스 로더가 크게 개선되었습니다. 이전 코드는 여전히 작동하지만 새 시스템으로 인해 구현이 더 쉬워졌습니다. 이 새로운 모델은 프록시 위임 모델입니다. 즉, 클래스 로더가 클래스를 찾을 수 없으면 상위 클래스 로더에게 클래스를 찾도록 요청한다는 의미입니다. 시스템 클래스 로더는 모든 클래스 로더의 조상입니다. 시스템 클래스 로더는 기본적으로 로컬 파일 시스템에서 클래스를 로드합니다. loadClass 메서드를 재정의하면 일반적으로 클래스를 로드하기 위해 여러 가지 방법이 시도됩니다. 많은 클래스 로더를 작성하면 이 복잡한 메서드를 계속해서 일부 수정한다는 사실을 알게 될 것입니다. Java 1.2에서 loadClass의 기본 구현에는 클래스를 찾는 가장 일반적인 방법이 포함되어 있으며, findClass 메서드와 loadClass를 재정의하여 findClass 메서드를 적절하게 호출할 수 있습니다. 이것의 장점은 loadClass를 재정의할 필요가 없고 findClass만 재정의하면 되므로 작업 부하가 줄어든다는 것입니다.
새로운 메소드: findClass
이 메소드는 loadClass의 기본 구현에 의해 호출됩니다. findClass의 목표는 모든 클래스 로더 관련 코드를 포함하는 것입니다.
코드를 반복할 필요가 없습니다(예: 지정된 메소드가 실패할 때 시스템 클래스 로더 호출).
새로운 메소드: getSystemClassLoader
findClass 및 loadClass 메소드를 대체하는지 여부에 관계없이 getSystemClassLoader 메소드는 시스템 클래스 로더에 직접 액세스할 수 있습니다(findSystemClass를 통한 간접 액세스가 아님).
새로운 메소드: getParent
상위 클래스 로더에 요청을 위임하기 위해 이 메소드를 통해 해당 클래스 로더의 상위 클래스 로더를 얻을 수 있습니다. 사용자 정의 클래스 로더의 특정 메소드가 클래스를 찾을 수 없는 경우 요청을 상위 클래스 로더에 위임할 수 있습니다. 클래스 로더의 상위 클래스 로더에는 클래스 로더를 생성하는 코드가 포함되어 있습니다.
6부. 소스 코드
ClassLoader.java 컴파일하기
다음은 CompilingClassLoader.java 파일의 내용입니다.
import java.io.*;
/*
CompilingClassLoader는 Java 소스 파일을 동적으로 컴파일합니다. .class 파일이 존재하는지, .class 파일이 소스 파일보다 오래된 것인지 확인합니다.
*/
공용 클래스 CompilingClassLoader는 ClassLoader를 확장합니다.
{
//파일 이름을 지정하고, 디스크에서 전체 파일 내용을 읽고, 바이트 배열을 반환합니다.
private byte[] getBytes( String filename )에서 IOException이 발생합니다.
// 파일 크기를 구합니다.
파일 파일 = 새 파일(파일 이름);
긴 len = file.length();
//파일 내용을 저장할 만큼만 배열을 만듭니다.
바이트 원시[] = 새 바이트[(int)len];
//파일 열기
FileInputStream fin = new FileInputStream(파일);
// 모든 내용을 읽습니다. 읽을 수 없으면 오류가 발생한 것입니다.
int r = fin.read(raw);
if (r != len)
throw new IOException( "모두 읽을 수 없습니다. "+r+" != "+len );
// 파일을 닫는 것을 잊지 마세요.
fin.close();
// 이 배열을 반환합니다.
원시 반환;
}
// 지정된 Java 소스 파일을 컴파일하고 파일 매개변수를 지정하는 프로세스를 생성합니다. 컴파일이 성공하면 true를 반환하고, 그렇지 않으면
// 거짓을 반환합니다.
개인 부울 컴파일(String javaFile)이 IOException을 발생시킵니다.
//현재 진행상황 표시
System.out.println( "CCL: "+javaFile+" 컴파일 중..." );
//컴파일러 시작
프로세스 p = Runtime.getRuntime().exec( "javac "+javaFile );
// 컴파일이 끝날 때까지 기다립니다.
노력하다 {
p.waitFor();
} catch( InterruptedException 즉 ) { System.out.println( 즉 );
// 반환 코드를 확인하여 컴파일 오류가 있는지 확인합니다.
int ret = p.exitValue();
//컴파일 성공 여부를 반환합니다.
ret==0;을 반환합니다.
}
// 클래스 로더의 핵심 코드 - 클래스를 로드하면 필요할 때 자동으로 소스 파일을 컴파일합니다.
공용 클래스 loadClass( 문자열 이름, 부울 해결 )
ClassNotFoundException이 발생합니다.
//우리의 목적은 클래스 객체를 얻는 것입니다.
클래스 클래스 = null;
// 먼저 이 클래스가 처리되었는지 확인합니다.
clas = findLoadedClass(이름);
//System.out.println( "findLoadedClass: "+clas );
// 클래스 이름을 통해 경로 이름을 가져옵니다. 예: java.lang.Object => java/lang/Object
String fileStub = name.replace( ''''.'''', ''''/'''' );
// 소스 파일과 클래스 파일을 가리키는 객체를 생성합니다.
문자열 javaFilename = fileStub+".java";
문자열 classFilename = fileStub+".class";
파일 javaFile = 새 파일( javaFilename );
File classFile = 새 파일( classFilename );
//System.out.println( "j "+javaFile.lastModified()+" c "
//+classFile.lastModified() );
// 먼저 컴파일이 필요한지 확인합니다. 소스 파일은 존재하지만 클래스 파일은 존재하지 않거나, 둘 다 존재하지만 소스 파일이 존재하지 않는 경우
// Newer, 컴파일이 필요함을 나타냅니다.
if (javaFile.exists() &&(!classFile.exists() ||
javaFile.lastModified() > classFile.lastModified())) {
노력하다 {
// 컴파일합니다. 컴파일이 실패하면 실패 이유를 선언해야 합니다(오래된 클래스를 사용하는 것만으로는 충분하지 않습니다).
if (!compile( javaFilename ) || !classFile.exists()) {
throw new ClassNotFoundException( "컴파일 실패: "+javaFilename );
}
} catch(IOException 즉) {
// 컴파일 중에 IO 오류가 발생할 수 있습니다.
throw new ClassNotFoundException(ie.toString());
}
}
// 올바르게 컴파일되었는지 또는 컴파일이 필요하지 않은지 확인하고 원시 바이트 로드를 시작합니다.
노력하다 {
// 바이트를 읽습니다.
byte raw[] = getBytes( classFilename );
//클래스 객체로 변환
clas = 정의Class( name, raw, 0, raw.length );
} catch(IOException 즉) {
// 이는 실패를 의미하지 않습니다. 아마도 우리가 다루고 있는 클래스가 java.lang.Object와 같은 로컬 클래스 라이브러리에 있을 수 있습니다.
}
//System.out.println( "defineClass: "+clas );
//클래스 라이브러리에 있을 수도 있고 기본 방식으로 로드될 수도 있습니다.
if (class==null) {
clas = findSystemClass(이름);
}
//System.out.println( "findSystemClass: "+clas );
// 매개변수 해결이 true인 경우 필요에 따라 클래스를 해석합니다.
if(&& 클래스 != null 해결)
해결클래스(클래스);
// 클래스를 얻지 못한 경우 문제가 발생한 것입니다.
if (클래스 == null)
새로운 ClassNotFoundException(이름)을 던집니다.
// 그렇지 않으면 이 클래스 객체를 반환합니다.
반환 클래스;
}
}
CCRun.java
다음은 CCRun.java 파일입니다.
import java.lang.reflect.*;
/*
CCLRun은 CompilingClassLoader를 통해 클래스를 로드하여 프로그램을 실행합니다.
*/
공개 클래스 CCLRun
{
static public void main( String args[] )에서 예외 발생 {
//첫 번째 매개변수는 사용자가 실행하려는 기본 함수 클래스를 지정합니다.
문자열 progClass = args[0];
//다음 매개변수는 이 기본 함수 클래스에 전달되는 매개변수입니다.
String progArgs[] = 새로운 String[args.length-1];
System.arraycopy(args, 1, progArgs, 0, progArgs.length );
// CompilingClassLoader 생성
CompilingClassLoader ccl = new CompilingClassLoader();
//CCL을 통해 기본 함수 클래스를 로드합니다.
클래스 클래스 = ccl.loadClass( progClass );
// 리플렉션을 사용하여 메인 함수를 호출하고 매개변수를 전달합니다.
// 메인 함수의 매개변수 유형을 나타내는 클래스 객체를 생성합니다.
클래스 mainArgType[] = { (new String[0]).getClass() };
// 클래스에서 표준 메인 함수를 찾습니다.
메소드 main = clas.getMethod( "main", mainArgType );
// 매개변수 목록을 만듭니다. 이 경우 문자열 배열입니다.
객체 argsArray[] = { progArgs };
// 메인 함수를 호출합니다.
main.invoke( null, argsArray );
}
}
Foo.java
다음은 Foo.java 파일의 내용입니다.
공개 클래스 푸
{
static public void main( String args[] )에서 예외가 발생합니다.
System.out.println( "foo! "+args[0]+" "+args[1] );
새로운 바( args[0], args[1] );
}
}
Bar.java
다음은 Bar.java 파일의 내용입니다.
수입 baz.*;
공개 수업 바
{
공개 바( 문자열 a, 문자열 b ) {
System.out.println( "bar! "+a+" "+b );
새로운 Baz(a,b);
노력하다 {
클래스 booClass = Class.forName( "부" );
객체 boo = booClass.newInstance();
} catch(예외 e) {
e.printStackTrace();
}
}
}
바즈/Baz.java
다음은 baz/Baz.java 파일의 내용입니다.
패키지 바즈;
공개 수업 바즈
{
공개 Baz( 문자열 a, 문자열 b ) {
System.out.println( "baz! "+a+" "+b );
}
}
부.자바
다음은 Boo.java 파일의 내용입니다.
공개 수업 부
{
공개부() {
System.out.println( "부!" );
}
}
7부. 요약 요약 이 기사를 읽은 후에 사용자 정의 클래스 로더를 작성하면 Java 가상 머신의 내부로 깊이 들어갈 수 있다는 것을 깨달았습니까? 모든 리소스에서 클래스 파일을 로드하거나 동적으로 생성할 수 있으므로 이러한 기능을 확장하여 관심 있는 많은 작업을 수행할 수 있고 몇 가지 강력한 기능을 완료할 수도 있습니다.
ClassLoader에 관한 다른 주제 이 기사의 시작 부분에서 언급한 것처럼 사용자 정의 클래스 로더는 Java 임베디드 브라우저와 애플릿 브라우저에서 중요한 역할을 합니다.