웹로직 동적 반영에 대한 포스팅이 올라왔다.

http://sarc.io/index.php/miscellaneous/463-2016-05-25-16-26-51

이와 관련하여 자바 클래스 로딩에 대한 내용을 정리해보려고 한다.

 

Class Loader란?

Class Loader는 자바 바이트코드를 읽어들여 클래스 객체를 생성하는 역할을 담당한다. 좀 더 자세히 알아보자.

자바는 동적으로 클래스를 읽는다. 런타임 시에 모든 코드가 JVM에 링크, 로딩되는 것이다. 자바의 런타임 라이브러리인 rt.jar도 마찬가지다.

이러한 동적인 클래스 로딩을 담당하는 것이 Class Loader이며, 자바는 기본적으로 java.lang.ClassLoader라는 Class Loader를 제공한다.

역으로 동적으로 클래스를 로딩한다는 것은 JVM은 클래스에 대한 정보(메소드, 필드, 상속관계)를 가지고 있지 않다는 것을 의미한다. 이러한 정보 역시 동적으로 확인되며 검증한다.

클래스 로딩 방식에는 load-time dynamic loading과 run-time dynamic loading이 있다.

load-time dynamic loading은 클래스를 로딩하는 과정에서 다시 필요한 클래스를 로딩한다. 예를 들어 HelloWorld 클래스 내에 System.out.println이 있다면 java.lang.System을 로딩할 것이다.

반면 run-time dynamic loading은 클래스 내 코드를 실행하는 과정에서 필요한 클래스를 로딩한다. Class.forName()을 사용하는 경우가 대표적이다.

 

클래스 로딩의 순서는?

1. Bootstrap Class Loader는 JVM이 초기화 시 필요한 클래스(jre/lib/rt.jar 등)를 로딩한다.
 
2. Extension Class Loader는 $JAVA_HOME/jre/lib/ext내 클래스를 로딩한다. (Bootstrap과 Extension을 묶어 Bootstrap으로 표현하는 경우도 있다)
 
3. System Class Loader는 애플리케이션이 사용하는 클래스를 로딩한다.
 
여기까지는 일반적인 자바 애플리케이션의 클래스 로딩이다. 만약 웹로직과 같은 애플리케이션 서버를 사용하는 경우 ServletContainerClassLoader나 ServletContextClassLoader 등이 추가로 존재하게 된다.

 

자바 스펙에 의해 Class Loader는 다음 조건을 충족해야 한다.

1. WEB-INF/lib보다 WEB-INF/classes를 먼저 로딩해야 한다. (의무사항)
2. war 파일 내부의 클래스를 컨테이너 레벨의 jar 파일보다 먼저 로딩한다. (권고사항)
 
 
Tomcat은?
 
자바는 매커니즘 상 parent-first & child-last 방식에 의하여 Class Loading한다. 그러나 일부 애플리케이션 서버는 이와 다르게 동작하기도 한다. 예를 들어 톰캣은 마치 parent-last & child-first 방식으로 Class Loading하는 것처럼 보인다. 컨테이너 레벨(톰캣은 Common이라고 표현)보다 애플리케이션 하위를 먼저 로딩하기 때문이다.
 
1. Bootstrap
2. WEB-INF/classes
3. WEB-INF/lib
4. System
5. $CATALINA_BASE/lib 하위의 unpacked 클래스
6. $CATALINA_BASE/lib 하위의 jar
7. $CATALINA_HOME/lib 하위의 unpacked 클래스
8. $CATALINA_HOME/lib 하위의 jar
 
만약 기존 자바 매커니즘대로 로딩하려면 <Loader delegate="true"/> 설정을 통해 강제 재조정할 수 있다.
 
1. Bootstrap
2. System
3. $CATALINA_BASE/lib 하위의 unpacked 클래스
4. $CATALINA_BASE/lib 하위의 jar
5. $CATALINA_HOME/lib 하위의 unpacked 클래스
6. $CATALINA_HOME/lib 하위의 jar
7. WEB-INF/classes
8. WEB-INF/lib
 
톰캣에서 System Class Loader에 의해 로딩되는 클래스는 다음과 같다.
 
  • $CATALINA_HOME/bin/bootstrap.jar
  • $CATALINA_HOME/bin/tomcat-juli.jar (만약 $CATALINA_BASE/bin/tomcat-juli.jar가 존재한다면 이것을 로딩함)
  • $CATALINA_HOME/bin/commons-daemon.jar (존재 시)
 
톰캣, JDK 8에서 System.getProperty("sun.boot.class.path"); 로 확인한 결과는 다음과 같다.
/jdk8/jre/lib/resources.jar:/jdk8/jre/lib/rt.jar:/jdk8/jre/lib/sunrsasign.jar:/jdk8/jre/lib/jsse.jar:/jdk8/jre/lib/jce.jar:/jdk8/jre/lib/charsets.jar:/jdk8/jre/lib/jfr.jar:/jdk8/jre/classes
 
System.getProperty("java.ext.dirs"); 로 확인한 결과는 다음과 같다.
/jdk8/jre/lib/ext:/usr/java/packages/lib/ext
 
System.getProperty("java.class.path"); 로 확인한 결과는 다음과 같다.
/apache-tomcat-9.0.0.M4/bin/bootstrap.jar:/apache-tomcat-9.0.0.M4/bin/tomcat-juli.jar