Java

[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를 서블릿(Java 클래스)로 변환하는 과정에서 바이트코드 생성
AOP 프레임워크
실행 전/후에 코드 삽입 (e.g., 로깅, 트랜잭션)
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;
        }
    }
);