클래스로더
• 개요
○ 자바 클래스로더는클래스를 메모리로 로드하는 JVM의 일부다.
(컴파일 시점이 아닌 실행시점에 클래스를 로딩할 수 있게 해주는 기술)
> 예를 들어 ClassA = new HelloWorld(); 라는 코드를 실행할 때, JVM은 HelloWorld 를 클래스로더를 통해 메모리에 로드 한다.
○ 자바의 기초 기능이며 클래스로더는 실행시간 중 클래스를 찾고 로딩하는 역할을 한다.
○ 클래스의 바이트 코드를 파일 시스템상의 클래스나, JAR와 같은 아카이브 형태로 동적 로딩할 수 있도록 지원해준다.
○ Java 프로그래머는 클래스 로더와 그 동작을 이해해야 한다.
클래스로더의 특징
I. 계층적(Hierarchical)
i. 클래스 로더는 계층적으로 생성 가능
ii. 상위(부모)클래스로더부터 하위(자식) 클래스 로더를 갖는것과 같다.
iii. 이 과정에서 계층형 구조를 갖게 된다.
iv. 최상위 클래스 로더는 부트스트랩 클래스 로더가 위치한다.
II. 위임형 로드 요청(Delegate Load Request)
i. 상위 클래스 로더가 로딩한 클래스가 우선권을 가진다.
ii. 예를 들어 클래스 로더가 상위로부터 각각 CL1 - CL2 - CL3 이라고 가정하면, CL3이 특정 클래스를 로딩 시 해당 클래스 로딩을 CL2로 요청하고, CL2는 다시 CL1으로 로딩을 요청한다.
III. 가시적인 규약(Visibility constraint)
i. 상위 클래스 로더를 먼저 참조하고, 클래스 로더는 일종의 범위 룰(Scope Rule)을 제공한다.
ii. 하위 클래스 로더는 상위 클래스 로더의 클래스를 위임형 로드 요청을 이용해 찾을 수 있다.
iii. 하지만 상위 클래스로더는 하위 클래스 로더가 로딩할 클래스를 사용할 수 없다.
iv. 또한, 상위 클래스 로더가 같은 하위 클래스 로더는 서로 로딩할 클래스를 사용할 수 없다.
IV. 클래스는 언로드 할 수 없음
i. 클래스 로더에 의해서 로딩된 클래스들은 언로드(Unload)될 수 없다.
ii. 클래스 로더에는 클래스 언로딩(Unloading)기능이 없다.
iii. 이를 구현하기 위해서는 클래스 로더를 삭제하고, 새로운 클래스 로더를 생성하여 다시 클래스 로더를 로딩하면 마치 재로드(Reload)되는 것 처럼 작동된다.
• 클래스로더 계층 (Hierarchy)
○ 클래스로더에는 상위-하위 클래스 로더가 있다.
- 이는 Super class - sub class 객체 관계와 유사하다.
○ BootStrap ClassLoader
- Java 클래스 로더 계층 구조의 루트
- JVM에 java.*으로 된 JDK 내부 클래스 및 패키지를 JVM에 로드한다.
예를 들자면 java.lang.String
○ Extension ClassLoader
- 부트 스트랩 클래스로더의 하위 클래스로더
- JDK의 확장 디렉토리에 있는 모든 JAR파일을 로드한다.
□ 클래스 경로에 다른 항목을 추가하지 않아도 JDK를 확장할 수 있는 편리한 방법
□ 단, 이 Extension ClassLoader와 BootStrap ClassLoader가 로드하는 기본 JDK클래스 및 확장 클래스 이외의 것은 참조할 수 없다.
○ System Classpath ClassLoader
- JVM 클래스 경로에서 클래스를 로드한다.
○ Application-specific ClassLoader
- 클래스패스 클래스로더의 하위 클래스로더
- 웹로직 서버 클래스로더는 여기에 포함
클래스 로더의 구조
○ 클래스 로더는 상위로부터 순서대로 부트스트랩, 확장, 시스템 클래스 로더가 순서대로 올라간다.
○ 즉 동일한 클래스가 여러 곳에 존재할 때 로딩되는 우선순위는 BootStrap>Extensions>System Class Loader 이다.
1) 부트스트랩(Bootstrap) Class Loader
I. 자바 가상 머신이 실행될 때 가장 먼저 실행되는 클래스 로더
II. JAVA실행에 필요한 기본적인 클래스들을 로딩한다. ($JAVA_HOME/jre/lib/rt.jar)
III. 다른 클래스 로더와 달리 자바가 아니라 네이티브 코드로 구현되어 있다.
2) 확장(Extensions) Class Loader
I. 추가로 로딩되는 클래스들로 JAVA 확장 클래스들이 로딩된다.($JAVA_HOME/lib/ext/*.jar)
II. 이 클래스들을 별도로 클래스패스(Classpath)에 설정되어 있지 않아도 로딩된다.
III. 다양한 보안 확장 기능등을 여기에서 로드한다.
3) 시스템(System) Class Loader
I. Classpath에 정의되거나 JVM옵션에서 -cp, -classpath에 지정된 클래스들이 로딩된다.
II. 애플리케이션의 클래스들을 로드한다고 할 수 있다.
III. 즉, 사용자가 지정한 $CLASSPATH 내의 클래스들을 로드한다.
4) 사용자 정의(User-Defined) Class Loader
I. 애플리케이션 사용자가 직접 코드 상에서 생성해서 사용하는 클래스 로더이다.
웹로직(WebLogic) 클래스 로더 이해
○ 웹로직 클래스 로더는 사용자 정의 클래스 로더이다.
○ 부모 클래스 로더는 시스템 클래스 로더이다.
○ EJB JAR, WAR, EAR을 로딩하는 세 종류의 클래스 로더가 있다.
1) EJB-JAR 클래스 로더
I. EJB를 JAR 형식으로 배포하면, JAR 1개당 EJB-JAR클래스 로더가 생성된다.
II. 즉, 서로 JAR 간에는 클래스를 참조할 수 없고, System 클래스 로더 이상의 상위 클래스 로더의 클래스들을 참조할 수 있다.
III. 아니면 필요한 클래스들을 동일한 JAR에 패키징해야 한다.
2) WAR 클래스 로더
I. JSP나 서블릿(Servlet)을 로딩하는 클래스 로더이다.
II. WAR 클래스 로더는 위의 클래스 로더의 특징을 가지고 있다.
III. 다만 주의할 점은 클래스 로딩 우선 순위를 일반적인 상위 클래스 로더보다 WEB-INF/classess 와 WEB-INF/lib 디렉토리를 우선 로딩할 수 있도록 설정 할 수 있다.
IV. 설정 방법은 웹 콘솔에서 PreferWebInfClassess를 true로 설정하면 된다.
3) EAR 클래스 로더
I. EAR를 로딩하는 클래스 로더이다.
II. 내부적으로 EJB-JAR 클래스 로더와 WAR 클래스 로더가 부모-자식관계로 생성된다.
i. 즉 서블릿/JSP에서 EJB를 참조하여 호출 가능하다.
ii. 이유는 서블릿/JSP가 로딩된 WAR 클래스 로더의 부모 클래스 로더가 EJB를 로딩하는 EJB-JAR 클래스 로더이기 때문이다. (위임형 로드요청)
III. 아래 그림의 클래스 로더구조에선 WebApp1은 EJB1, 2를 참조하여 호출할 수 있고, WebApp2와 WebApp3은 EJB3를 참조하여 호출할 수 있다. 하지만 EJB1/EJB2와 EJB3을 로딩하는 클래스 로더가 부모-자식 관계가 아니기에 서로 참조는 하지 못한다.
웹로직에서의 패키징 (Packaging)
1) 패키징을 할 때, 서블릿/JSP에서 EJB를 호출할 때, EJB의 클라이언트 클래스
(EJB Remote Interface, EJB Home Interface 등)와 EJB에서 공통으로 사용하는 공통 클래스를 어떻게 패키징할 것인가가 큰 이슈가 될 것이다.
I. WEB-INF/lib 또는 WEB-INF/classes 폴더에 EJB 클라이언트 클래스와 공통 클래스를 배포
II. EJB-JAR형태의 JAR로 패키징
III. CLASSPATH로 설정
IV. EJB-JAR 형태로 EAR에 배포
EAR 의 APP-INF/lib 또는 APP-INF/classes에 공통 클래스 배포
• 클래스 로딩
○ 클래스로더는 우선 캐시를 사용하여 이미 클래스가 로드 되었는지 확인한다.
- 이 과정은 디스크에서 클래스를 반복적으로 로드하는 대신 캐시 메모리 복사본을 사용함으로써 성능이 향상된다.
- 웹로직의 경우 DOMAIN_HOME/servers/weblogic_name/cache/classloader 에서 확인할 수 있다. 또는 시작쉘에서 따로 지정이 가능하다.
○ 만약 클래스를 캐시에서 찾을 수 없다면 local 에서 찾기 전 먼저 현재 클래스로더는 부모클래스로더에게 요청한다.
- 찾을 수 없다면 자신의 범위에서 찾아 로드한다.
- 상위/하위 클래스로더 모두에 있는 경우 무조건 상위클래스로더의 버전이 로드된다.
○ 웹 애플리케이션과 연관된 웹로직 클래스로더는 부모클래스로더에게 요청 전 먼저 local에서 찾을 수 있다.
- 이는 웹 애플리케이션이 애플리케이션 내부의 원하는 third-party 클래스들을 사용할 수 있게 해준다.
□ 예를 들어 사용하고 싶은 클래스 A가 있다고 할때, 애플리케이션에 올린 A 의 버전은 3 버전이고 부모클래스로더에 들어있는 A의 버전이 1일때 웹로직 설정을 통해 애플리케이션의 A (3버전)을 쓸 수 있다.
- prefer-web-inf-classes 설정으로 가능하다.
□ 기본값은 false 기에 따로 설정을 해두지 않는다면 무조건 부모클래스에 우선 요청한다.
○ 기본적으로는 실행중일 때 클래스를 업데이트 하려면 클래스로더를 새 클래스로더로 실행해야 하는데, 클래스로더가 교체되면 해당 클래스 로더 및 자손 클래스로더에서 로드된 모든 클래스들을 다시 로드해야만 한다.
§ 웹로직 클래스로더를 사용하면 일부분만 개별적으로 다시 로드가 가능하다.
• 응용프로그램 클래스 로딩
○ 만약 EAR안에 WAR/JAR를 포함해서 하나의 애플리케이션으로 올린 경우와, WAR, JAR를 따로따로 나뉘어 올린 경우를 살펴보면
- EAR파일 함께 배포한 경우 서블릿과 JSP가 EJB클래스를 찾을 수 있는 클래스 로더 배열이 생성된다.
- 따로 배포한 경우 WAR파일에 EJB홈 및 원격 인터페이스를 포함해야만한다.
□ JAR에 있는 클래스를 실행하기 위해 RMI 와 같은 클래스를 사용해야 한다.