Java/JVM

[JVM 밑바닥까지 파헤치기] 9. 클래스 로딩과 실행 서브시스템, 사례와 실전

noahkim_ 2024. 12. 24. 04:04

저우즈밍 님의 "JVM 밑바닥까지 파헤치기" 책을 정리한 포스팅 입니다

 

1. 톰켓: 정통 클래스 로더 아키텍처

항목 설명
여러 개의 클래스 로더 사용
톰캣은 여러 개의 클래스 로더를 사용하여 웹 애플리케이션마다 격리된 클래스 로딩 구조를 유지함
공유 라이브러리
공통 라이브러리는 클래스 로더 위임 모델을 통해 공유됨 (예: lib, classes 디렉토리 사용)
웹 앱 클래스 로더 디렉토리
/lib: 톰캣 자체 및 모든 웹앱 공통
/webapp/WEB-INF: 개별 웹앱 전용
핫 스왑 지원 (JSP)
JSP 파일 수정 시 서버 재시작 없이 자동 컴파일 및 적용됨

 

2. OSGi: 유연한 클래스 로더 아키텍처

  • Java 기반의 동적 모듈 시스템 (OSGi = Open Services Gateway initiative)
항목 설명
번들 (Bundle)
JAR 형식의 모듈 단위
실행 가능한 클래스 라이브러리
클래스 로더 특징
각 번들은 고유의 클래스 로더를 가짐
→ 모듈 간 독립성 유지
가시성 제어
Import-Package, Export-Package를 통해의존 패키지와 공개 패키지를 명시적으로 선언
동적 기능 관리
번들의 동적 로딩, 언로드, 갱신이 가능함
→ 전체 재시작 없이 일부 기능만 교체 가능 (핫 스와프)
핫 스왑 수준
모듈 수준에서의 핫 스와프 지원 (Tomcat보다 더 정교한 유연성 제공)

 

3. 동적 프락시 구현

정적 바이트코드 생성 기술

기술/도구 설명 예시
javac 컴파일러
자바 소스코드를 바이트코드로 정적 컴파일
 
JSP 컴파일러
JSP를 서블릿 클래스로 변환하는 과정에서 바이트코드 생성
 
AOP 프레임워크 실행 전/후에 코드 삽입 - AspectJ: 정적 위빙 
- Spring AOP: 런타임 프록시 활용

 

동적 프락시

  • 런타임에 프락시 객체를 생성하는 기술
  •  원래 객체 정보 없이도 프락시 객체를 생성할 수 있음
항목 JDK Proxy (JDK 표준 API) CGLIB
동작 방식 인터페이스를 구현한 프록시 객체 생성 바이트코드 생성 라이브러리
기반 인터페이스 클래스 상속 (서브클래스 생성)
제약 인터페이스 필요
final 클래스/메서드는 제한
속도 상대적으로 빠름
약간 느림 (동적 클래스 생성 overhead)
사용 사례 인터페이스 Bean
인터페이스 없는 Bean (Spring AOP 내부 자동 선택)

 

예시) java.lang.reflect.Proxy

더보기
Proxy.newProxyInstance(
    obj.getClass().getClassLoader(),
    obj.getClass().getInterfaces(),
    this
);

 

예시) CGLIB

더보기
TargetService proxy = (TargetService) Enhancer.create(
    TargetService.class,
    new MethodInterceptor() {
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            System.out.println("Before method: " + method.getName());
            Object result = proxy.invokeSuper(obj, args);
            System.out.println("After method: " + method.getName());
            return result;
        }
    }
);