[ 개요 ]
- 많은 서버 애플리케이션과 마찬가지로, Tomcat 은 컨테이너의 여러 부분과 컨테이너에서 실행되는 웹 애플리케이션이 서로 다른 클래스와 리소스 영역에 접근할 수 있도록 다양한 Class Loader 를 설치한다. (java.lang.ClassLoader 를 구한하는 클래스들)
- 이 매커니즘은 서블릿 스펙 2.4 버전의 9.4와 9.6 섹션에 정의된 기능을 제공하는데 사용된다.
- Java 환경에서 Class Loader 는 부모-자식 트리구조로 배치된다.
- 일반적으로 Class Loader 가 특정 Class 나 Resource 를 로드하도록 요청받으면 먼저 부모 Class Loader 에 요청을 위임하고, 부모 Class Loader 가 요청된 클래스나 리소스를 찾을 수 없는 경우에만 자신의 영역에서 찾는다.
- WEB_Application Class Loader 의 모델은 아래에서 설명하는 것처럼 약간 다르지만, 주요 원칙은 동일하다.
- Tomcat 이 시작되면 다음과 같이 부모-자식 관계로 구성된 Class Loader 세트를 생성한다. (부모 클래스로더가 자식 클래스로더 위에 있음)
Bootstrap
|
System
|
Common
/ \
Webapp1 Webapp2 ...
- Class Loader 가 표시하는 Class 및 Resource 의 소스를 포함하여 이러한 각 Class Loader 의 특성에 대해서는 다음 섹션에서 자세히 설명한다.
[ Class Loader 정의 ]
- 위 다이어그램에 표시된대로, Tomcat 은 초기화 될 때 다음과 같은 Class Loader 들을 생성한다.
1. Bootstrap
- 이 Class Loader 는 Java Virtual Machine 이 제공하는 기본 런타임 클래스들과 시스템 확장 디렉토리($JAVA_HOME/jre/lib/ext) 에 있는 JAR 파일의 클래스들을 포함한다.
- 참고: 일부 JVM 은 이를 하나 이상의 Class Loder 로 구현하거나, Class Loader 로 전혀 보이지 않을 수 있다.
2. System
- 이 Class Loader 는 일반적으로 CLASSPATH 환경변수의 내용으로부터 초기화 된다.
- 이러한 모든 Class 들은 Tomcat 내부 클래스와 WEB_Application 둘다 볼 수 있다.
- 하지만, 표준 Tomcat 시작스크립트 ($CATALINA_HOME/bin/catalina.sh 또는 %CATALINA_HOME%/bin/catalina.bat) 는 CLASSPATH 환경변수 자체의 내용을 완전히 무시하고, 대신 다음의 항목에서 System Class Loader 를 구축한다.
1) $CATALINA_HOME/bin/bootstrap.jar
- Tomcat 서버를 초기화 하는데 사용되는 main() 메소드와 종속된 Class Loader 구현 클래스들을 포함한다.
2) $CATALINA_(BASE|HOME)/bin/tomcat-juli.jar
- 로깅 구현 클래스들이며, Tomcat JULI 로 알려진 java.util.logging API 에 대한 개선된 클래스와 Tomcat 내부적으로 사용되는 package 이름이 변경된 Apache Common Logging 라이브러리 복사본을 포함한다.
- 만약 tomcat-juli.jar 파일이 $CATALINA_BASE/bin, $CATALINA_HOME/bin 둘다 있다면 $CATALINA_BASE/bin 의 파일이 사용되며, 특정 로깅 구성에서 유용하다.
3) $CATALINA_HOME/bin/commons-daemon.jar
- Apache Commons Daemon 프로젝트의 클래스들이며, 이 JAR 파일은 catalina.sh|bat 스크립트에의해 만들어진 CLASSPATH 에는 없지만 bootstrap.jar 의 manifest 파일에서 참조된다.
1004lucifer
3. Common
- 이 Class Loader 는 Tomcat 내부 Class와 모든 WEB_Application 에 있는 추가 Class를 포함한다.
- 일반적으로 애플리케이션 Class 는 여기에 위치하면 안된다.
- 이 Class Loader 가 검색하는 위치는 $CATALINA_BASE/conf/catalina.properties 파일의 common.loader 속성에 의해 정의된다.
- 기본 설정은 아래 리스트의 순서대로 검색한다.
1) $CATALINA_BASE/lib 경로의 압축 해제된 Class 와 Resource
2) $CATALINA_BASE/lib 경로의 JAR 파일들
3) $CATALINA_HOME/lib 경로의 압축 해제된 Class 와 Resource
4) $CATALINA_HOME/lib 경로의 JAR 파일들
- 기본적으로 아래와 같은 항목들이 포함된다.
1) annotations-api.jar - Jakarta Annotations 3.0 Classes.
2) catalina.jar - Tomcat 의 Catalina Servlet 컨테이너 부분 구현체
3) catalina-ant.jar - (옵션) Manager 웹 애플리케이션 작업을 위한 Tomcat Catalina Ant Task
4) catalina-ha.jar - (옵션) Tribes 기반의 세션 클러스터링 기능을 제공하는 고가용성 패키지
5) catalina-ssi.jar - (옵션) 서버 사이드 Include 모듈
6) catalina-storeconfig.jar - (옵션) 현재 상태에서 XML 설정파일 생성
7) catalina-tribes.jar - (옵션) 고가용성 패키지에서 사용하는 그룹 통신 패키지
8) ecj-*.jar - (옵션) JSP 를 Servlet 으로 컴파일하는데 사용되는 Eclipse JDT Java 컴파일러
9) el-api.jar - (옵션) EL 6.0 API
10) jakartaee-migration-*-shaded.jar - (옵션) Java_EE_8 에서 Jakarta_EE_9 로 웹 애플리케이션 변환 제공
11) jasper.jar - (옵션) Tomcat Jasper JSP 컴파일러와 런타임
12) jasper-el.jar - (옵션) Tomcat EL 구현체
13) jaspic-api.jar - (옵션) Jakarta Authentication 3.1 API
14) jsp-api.jar - (옵션) Jakarta Pages 4.0 API
15) tomcat-api.jar - (옵션) Tomcat 에서 정의한 여러 인터페이스
16) tomcat-coyote.jar - Tomcat connector 와 Util Class
17) tomcat-dbcp.jar - (옵션) (package 이름 변경된)Apache_Commons_Pool_2 와 Apache_Commons_DBCP_2 를 구현한 DB_Connection_Pool 구현체
18) tomcat-i18n-**.jar - (옵션) 다른 언어용 리소스 번들을 포함하는 JAR 이며, (영어)기본 번들이 각 개별 JAR 에도 포함되어 있으므로, 메시지 국제화가 필요하지 않은경우 안전하게 제거 가능함.
19) tomcat-jdbc.jar - (옵션) Tomcat_JDBC_Pool 로 알려진 대체 DB_Connection_Pool 구현체. 자세한 내용은 문서링크 참고.
20) tomcat-jni.jar - Tomcat Native 라이브러리와의 통합 제공
21) tomcat-util.jar - Apache Tomcat 의 다양한 컴포넌트에서 사용되는 공통 Class
22) tomcat-util-scan.jar - Tomcat 에서 사용하는 Class 스캔 기능 제공
23) tomcat-websocket.jar - (옵션) Jakarta WebSocket 2.2 구현체
24) websocket-api.jar - (옵션) Jakarta WebSocket 2.2 API
25) websocket-client-api.jar - (옵션) Jakarta WebSocket 2.2 Client API
4. WebappX
- 단일 Tomcat 인스턴스에 배포되는 각각의 WEB_Application 마다 Class Loader 가 생성된다.
- WEB_Application 의 /WEB-INF/classes 디렉토리에 있는 모든 압축 해제된 Class 와 Resource, 그리고 /WEB-INF/lib 디렉토리에 있는 JAR 파일들에 있는 Class 와 Resource 들은 해당 WEB_Application 에서는 접근 가능하지만 다른 WEB_Application 에서는 접근할 수 없다.
- 위에서 언급했듯이 (Servlet v2.4 스펙 9.7.2 섹션의 Web Application Classloader 권장사항에 따라) WEB_Application Class Loader 는 기본 Java 위임 모델과 다르다.
- WEB_Application 의 WebappX Class Loader 에서 Class 를 로드하는 요청이 처리될 때, 이 Class Loader 는 위임하기전에 로컬 영역에서 먼저 검색한다.
- 예외가 있는데 JRE 기본 클래스의 일부 클래스는 오버라이드 할 수 없다.
- XML 파서 컴포넌트와 같이 업그레이드 가능한 모듈 기능을 사용하여 오버라이드 할 수 있는 일부 예외가 있다.
- 마지막으로, WEB_Application Class Loader 는 항상 Tomcat 에서 구현된 (Servlet, JSP, EL, WebSocker)사양에 대한 Jakarta EE API 클래스에 대해 먼저 위임한다.
- Tomcat 의 다른 모든 Class Loader 는 일반적인 위임 패턴을 따른다.
- 따라서 WEB_Application 관점에서 Class 나 Resource 로드는 아래 영역 순서대로 검색한다.
1) JVM 의 Bootstrap Class
2) WEB_Application 의 /WEB-INF/classes
3) WEB_Application 의 /WEB-INF/lib/*.jar
4) System Class Loader Class (위에 설명됨)
5) Common Class Loader Class (위에 설명됨)
- 만약 WEB_Application Class Loader 설정에 <Loader delegate="true" /> 설정이 있으면 순서는 아래와 같다.
1) JVM 의 Bootstrap Class
2) System Class Loader Class (위에 설명됨)
3) Common Class Loader Class (위에 설명됨)
4) WEB_Application 의 /WEB-INF/classes
5) WEB_Application 의 /WEB-INF/lib/*.jar
[ XML Parser 와 Java ]
- 이전 버전의 Tomcat 에서는 모든 WEB_Application 에서 사용하는 파서를 변경하기위해 Tomcat 라이브러리 디렉토리에서 XML 파서를 간단히 교체할 수 있었다.
- 하지만 최신 버전의 Java 를 실행할 때는 일반적인 Class Loader 위임 프로세스가 이 방법보다는 JDK 내부 구현된것을 우선적으로 선택하기 때문에 이 방법이 효과적이지 않다.
- Java 는 업그레이드 가능한 모듈이라는 매커니즘을 지원하여 (W3C의 DOM, SAX 와 같은) JCP 외부에서 만들어진 API 교체를 허용하며, 이 방법은 XML 파서 구현체를 업데이트 하는데 사용될 수 있다.
- JRE 컴포넌트를 오버라이딩 하는것은 위험이 따른다.
- 만약 오버라이드하는 컴포넌트가 100% 호환되는 API 를 제공하지 않는경우에는 Tomcat 및 배포된 Application 에 오류가 발생할 위험이 있다. (ex: Xerces 가 제공하는 API 가 JRE 에서 제공하는 XML API 와 100% 호환되지 않는경우)
[ 고급 구성 ]
- 아래와 같이 더 복잡한 Class Loader 계층 구조를 구성할수도 있다.
- 기본적으로 Server 와 Shared Class Loader 는 정의되어 있지 않으며, 위에서 보여진 단순화된 계층 구조가 사용된다.
- 이러한 더 복잡한 계층구조는 conf/catalina.properties 에서 server.loader 와 shared.loader 속성에 값을 정의하여 사용할 수 있다.
Bootstrap
|
System
|
Common
/ \
Server Shared
/ \
Webapp1 Webapp2 ...
- Server Class Loader 는 Tomcat 내부에서만 사용 가능하며, WEB_Application 에서는 노출되지 않는다.
- Shared Class Loader 는 모든 WEB_Application 에서 사용 가능하며 WEB_Application 간에 (코드)모듈을 공유하는데 사용할 수 있다.
- 하지만 모듈을 업데이트 하려면 Tomcat 을 재기동 해야 한다.
[ ★작성자 내용 추가★ ]
- conf/catalina.properties 파일에 기본적으로 아래와 같이 설정되어 있다.
common.loader="${catalina.base}/lib","${catalina.base}/lib/*.jar","${catalina.home}/lib","${catalina.home}/lib/*.jar"
server.loader=
shared.loader=
- common.loader : Tomcat Engine, Application 모두에서 사용 가능
- server.loader : Tomat Engine 에서만 사용 가능
- shared.loader : (모든 Context) Application 에서만 사용 가능
* server.loader, shared.loader 설정은 공백으로 두면 common.loader 의 값이 해당 설정으로 사용된다.
- Tomcat 에서 JNDI 암호화 패스워드를 위해 tomcat-dbcp.jar 를 상속받은 모듈을 개발하기도 하는데, 해당 모듈이 Application 의 package 또는 Class 와 충돌하지 않도록 아래와 같이 설정이 가능하다.
common.loader="${catalina.base}/lib","${catalina.base}/lib/*.jar","${catalina.home}/lib","${catalina.home}/lib/*.jar"
server.loader="/home/tomcat/jndi/jndi_커스텀_모듈.jar"
shared.loader=
- 많이들 ({_Tomat 설치경로_}/lib 디렉토리) common.loader 에 Application 에서 사용하는 jar 라이브러리 파일을 넣는 경우가 있는데 Tomcat 공식 문서에서는 해당 위치에 넣는 것을 권장하지 않는다.
- 따라서 3rd Party 솔루션인경우 해당 설치 위치의 jar 파일을 setenv.sh 와 같은 환경변수에 추가하거나 jar 만 따로 제공하는 모듈인경우 Application 의 /WEB-INF/lib/ 또는 shared.loader 디렉토리에 넣는 것을 권장한다.
참고
- https://tomcat.apache.org/tomcat-11.0-doc/class-loader-howto.html
댓글
댓글 쓰기