Java

자바 클래스 로더, 200% 활용하기

_침묵_ 2006. 10. 19. 02:31

출처 :http://www.zdnet.co.kr/news/enterprise/etc/0,39031164,39148280,00.htm

원문 :http://articles.techrepublic.com.com/5100-3513_11-6080883.html?tag=search

 

 

자바 클래스 로더, 200% 활용하기

 

 

클래스 로더는 자바의 강력한 기능 중 하나다. 왜 커스터마이즈드 클래스 로더를 사용해야 하고, 자체 클래스 로더를 어떻게 만들며, 클래스 로딩 메커니즘을 잘 아는 것이 어떤 도움이 되는지에 대해 알아본다.

클래스 로더는 자바의 강력한 기능이다. 그러나 개발자들은 "Hello, world" 애플리케이션 보다 복잡한 프로그램을 작성하는데 필수적이지만 클래스 로딩 컴포넌트에 대해 잊어버리는 경우가 많다. 클래스 로더는 런타임에 클래스 파일을 찾고 로딩하는 임무를 맡는다. 자바에서는 상이한 클래스 로더를 사용하는 것이 가능하며, 커스터마이즈드 클래스 로더를 사용해도 된다.

자바 프로그램은 다수의 클래스 파일로 구성되며 각 클래스 파일은 하나의 자바 클래스와 대응된다. 이들 클래스 파일은 스태틱(static)하게 빌드된 C 프로그램처럼 메모리에 한꺼번에 로드되지 않고 온디맨드 방식으로 로드된다. 클래스 로더의 역할은 여기에서 시작된다.

왜 커스터마이즈드 클래스 로더를 사용하나
소스(.class 혹은 .jar 파일)에서 플랫폼에 독립적인 컴파일된 바이트 코드를 추출하며 JVM 메모리 공간에 로드해 이곳에서 인터프리트되고 실행되도록 한다. 기본 설정은 애플리케이션의 각 클래스가 java.lang.ClassLoader 인스턴스에 의해 로드된다. 이 클래스는 손쉽게 상속(inherit) 되므로 기능을 확장할 수 있다.

기본적인 java.lang.ClassLoader 는 로컬 파일시스템에서만 클래스를 로드할 수 있다. 자바는 로컬 하드 드라이브나 네트워크 이외의 장소에서 클래스를 가져올 수 있는 유연성을 충분히 제공하며 실제 로드가 일어나기 전에 특별한 기능을 수행하도록 할 수도 있다. 예를 들어 애플리케이션은 웹사이트나 FTP 에 존재하는 플러그-인 크래스의 새로운 버전을 주기적으로 검사하고 디지털 시그니처를 자동으로 확인한 후 신뢰성 있는 코드만 실행되도록 할 수 있다. 잘 아려진 애플리케이션 서버의 다수가 자체적인 클래스 로더를 사용한다.

소위 부트스트랩 클래스 로더로 불리는 이런 클래스 로더들이 기본적으로 사용된다. 즉 java.lang.Object 나 rt.jar 파일에 위치하고 있는 다른 런타임 코드를 메모리로 로드하는 역할을 하게 된다. 자바 랭귀지 스펙(Java Language Specification)은 부트스트랩 클래스 로더에 대해 세부사항을 제공하지 않기 때문에(네이티브(native) 구현을 하므로) JVM마다 기본 클래스 로더의 동작은 다르다. 일부 웹 페이지에서 동작하는 애플릿을 봤다면 이미 커스텀 클래스 로더를 사용해 본 것이다. 브라우저에 내장된 애플릿 뷰어는 원격 서버의 웹사이트를 접근해 HTTP로 로(raw) 바이트 코드 파일을 전송하고, JVM 내부의 클래스로 이를 전환하는 클래스 로더를 포함하기 때문이다.

자체 클래스 로더 작성
부트스트랩 클래스 로더를 제외한 클래스 로더는 부모 클래스 로더가 있으며 이는 클래스 로더를 로드한 클래스 로더이다. 가장 중요한 것은 부모 클래스 로더를 정확하게 설정하는 것이다. 그 다음 부모 클래스 로더의 getParent() 메쏘드를 사용하여 클래스 요청을 위임한다 (예. 커스텀 클래스 로더가 당신이 만든 특별한 메쏘드를 사용하여 클래스를 찾을 수 없을 경우) 컨스트럭터에서 java.lang.ClassLoader 컨스트럭터의 파라미터로 부모 클래스 로더를 설정한다.

public class MyClassLoader extends ClassLoader{

public MyClassLoader(){
super(MyClassLoader.class.getClassLoader());
}

loadClass(Straing name) 메쏘드는 우리가 만든 클래스로더의 엔트리 포인트이다. 파라미터 name은 FQCN(fully qualified class name), 즉 패키지를 갖춘 클래스 네임이다. 만약 부모 클래스 로더가 정확하게 설정됐다면 MyClassLoader가 loadClass(String name)에 의해 클래스를 로드하도록 요청받았지만 클래스를 로드할 수 없을 경우 부모를 먼저 확인하게 된다. 부모도 클래스를 찾을 수 없다면 findClass(String name) 메쏘드가 호출된다.findClass(String name)의 기본 구현은 대부분의 개발자가 너무나 잘 알고 있는 ClassNotFoundException을 발생시킨다.커스텀 클래스 로더 개발자들은 java.lang.ClassLoader를 상속받을 때 이 메쏘드를 대체해야 한다.

findClass() 메쏘드의 목적은 우리의 로더가 실패한 경우 시스템 클래스 로더를 호출하는 것과 같은 다른 코드를 복제하지 않고서도 MyClassLoader 를 위한 특수 코드를 모두 포함하는 것이다. 이 메쏘드에서 ClassLoader 는 임의의 코드에서 바이트 코드를 가져올 필요가 있다. 바이트 코드가 추출되면 메쏘드는 defineClass() 를 호출해야 한다. 로드된 클래스를 위해 ClassLoder 의 어떤 인스턴스가 메쏘드를 호출했는지는 매우 중요하다. 그러므로 두 개의 ClassLoder 인스턴스가 동일한 혹은 상이한 소스의 바이트 코드를 정의한다면 정의된 클래스는 다르게 다뤄진다.

동일한 소스에서 MyCoolClass 바이트 코드를 찾을 수 있는 두 개의 유사한 클래스 로더 MyClassLoader1과 MyClassLoder2의 예를 들어보자. 만약 애플리케이션이 MyCoolClass 인스턴스 두 개를 각 클래스 로더를 이용해 독립적으로 로드한다면(coolClass1은 MyClassLoader1을 통해 coolClass2는 MyClassLoader2를 통해서 한다고 가정하자), MyCoolClass.class도 독립적으로 정의된다. 다음의 코드를 실행하면:

MyCoolClass coolClass1 = (MyCoolClass)coolClass2;

ClassCastException이 발생된다. (클래스 로딩 메커니즘을 잘 모르는 개발자는 이 익셉션을 자주 받게 된다.)상이한 로더에 의해 정의되므로 JVM은 두 개의 완전히 다른 클래스 타입(type)을 보게 된다.coolClass1과 coolClass2은 동일한 클래스 타입에서 나왔고 동일한 소스에서 로드됐음에도 불구하고 그 변수들의 타입은 호환되지 않는다.

findClass()와 loadClass()를 대체할 때 마다 getSystemClassLoader() 메쏘드를 이용해 실제 ClassLoader 오브젝트의 형태로 시스템 ClassLoader에 직접 접근이 가능하다. 또한 findSystemClass(String name) 호출을 통해 암묵적으로도 접근할 수 있다. getParent() 메쏘드를 사용하면 부모 클래스 로더를 사용할 수 있다. Listing A는 실제 수행할 준비가 되어 있는 커스텀 클래스 로더의 예이다.

클래스 로딩 메커니즘을 잘 알고 있다면 애플리케이션의 ClassNotFound나 ClassCastException 에러를 디버깅할 때 결국 도움이 된다. 특히 애플리케이션이 써드 파티 애플리케이션 서버 내부에서 동작할 때 매우 중요한데 이런 애플리케이션 서버들이 독자적인 그리고 복잡한 클래스 로더를 사용하는 경우가 많기 때문이다.@

Peter V. Mikhalenko는 도이치 뱅크에서 비즈니스 컨설턴트로 일하고 있는 썬의 자격증을 소유한 전문가 (Sun certified professional) 이다.

 

 

'Java' 카테고리의 다른 글

EXCEPTION_ACCESS_VIOLATION [Java Exception]  (0) 2006.11.01
Jakarta 프로젝트의 regexp(정규식) 패키지 사용하기  (0) 2006.09.14
Log4j 튜토리얼  (0) 2006.09.14