Skip to content

Latest commit

 

History

History
61 lines (46 loc) · 4.4 KB

File metadata and controls

61 lines (46 loc) · 4.4 KB

spring-instrument — JVM 계측의 진입점

한 줄 정의

spring-instrument는 JVM이 시작 시점에 넘겨주는 java.lang.instrument.Instrumentation 인스턴스를 가로채 정적 필드에 보관해 두는, 단 하나의 자바 에이전트 클래스로 이루어진 모듈이다.

이 모듈이 푸는 문제

JPA의 지연 로딩, AspectJ의 로드타임 위빙(LTW, Load-Time Weaving) 같은 기능은 클래스가 클래스로더에 로드되는 바로 그 순간 바이트코드를 변형(transform)할 수 있어야 한다. 자바는 이 능력을 Instrumentation 인터페이스로 노출하는데, 이 인터페이스는 오직 JVM이 자바 에이전트의 premain/agentmain 콜백에 인자로 한 번 건네줄 때만 손에 넣을 수 있다. 애플리케이션 코드 어디에서도 new Instrumentation()을 할 수 없고, 그냥 조회하는 API도 없다.

문제는 이 Instrumentation 객체를 받는 콜백(premain)이 애플리케이션의 main보다도 먼저, Spring 컨테이너가 존재하기 한참 전에 호출된다는 점이다. 그래서 그 순간 받은 객체를 어딘가에 저장해 두었다가, 나중에 Spring의 LoadTimeWeaver가 필요할 때 꺼내 쓸 다리가 필요하다.

spring-instrument는 정확히 그 다리 역할만 한다. JVM이 주는 Instrumentationstatic volatile 필드에 저장하고, 나중에 getInstrumentation()으로 돌려준다. 그게 전부다. 가볍고 의존성이 전혀 없기 때문에 -javaagent: 옵션으로 부트클래스패스에 안전하게 끼워 넣을 수 있다.

의존 관계

   ┌──────────────────────────────┐
   │  JVM  (-javaagent 옵션)        │
   │  premain / agentmain 호출      │
   └──────────────┬───────────────┘
                  │ Instrumentation 전달
                  ▼
   ┌──────────────────────────────┐
   │  spring-instrument            │   ← 의존성 0개 (JDK만 사용)
   │  InstrumentationSavingAgent   │
   └──────────────┬───────────────┘
                  │ getInstrumentation()
                  ▼
   ┌──────────────────────────────┐
   │  spring-context               │
   │  InstrumentationLoadTimeWeaver│
   │  DefaultContextLoadTimeWeaver │
   └──────────────────────────────┘
  • 의존하는 모듈: 없음. JDK의 java.lang.instrument 패키지만 사용한다. 이 0-의존성이 에이전트 JAR로서 핵심 설계 제약이다.
  • 이 모듈을 의존(소비)하는 쪽: spring-contextInstrumentationLoadTimeWeaver가 런타임에 InstrumentationSavingAgent.getInstrumentation()을 호출해 위빙에 쓸 Instrumentation을 확보한다. 단, 컴파일 의존이 아니라 클래스 존재 여부를 ClassUtils.isPresent로 확인하는 느슨한 결합이다.

하위 챕터

  1. 자바 에이전트와 InstrumentationSavingAgentpremain/agentmain 콜백, manifest 속성, Instrumentation 저장 메커니즘.
  2. LoadTimeWeaver와의 연결 — 저장된 Instrumentationspring-context가 어떻게 꺼내 클래스 변형에 쓰는가.

전체 패키지 구조 ASCII 맵

spring-instrument/src/main/java
└── org/springframework/instrument
    ├── InstrumentationSavingAgent.java   ← 유일한 기능 클래스 (자바 에이전트)
    └── package-info.java                 ← "Core package for byte code instrumentation"

spring-instrument.gradle (manifest 속성)
    ├── Premain-Class:  InstrumentationSavingAgent   ← JVM 시작 시 에이전트
    ├── Agent-Class:    InstrumentationSavingAgent   ← Attach API 동적 로드
    ├── Can-Redefine-Classes:    true
    ├── Can-Retransform-Classes: true
    └── Can-Set-Native-Method-Prefix: false

모듈 전체가 기능 클래스 단 하나(InstrumentationSavingAgent)와 패키지 설명 파일로만 구성된 극단적으로 작은 모듈이다. 작지만 LTW 기능 전체의 토대가 되는 진입점이다.