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이 주는 Instrumentation을 static 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-context의InstrumentationLoadTimeWeaver가 런타임에InstrumentationSavingAgent.getInstrumentation()을 호출해 위빙에 쓸Instrumentation을 확보한다. 단, 컴파일 의존이 아니라 클래스 존재 여부를ClassUtils.isPresent로 확인하는 느슨한 결합이다.
- 자바 에이전트와 InstrumentationSavingAgent —
premain/agentmain콜백, manifest 속성,Instrumentation저장 메커니즘. - LoadTimeWeaver와의 연결 — 저장된
Instrumentation을spring-context가 어떻게 꺼내 클래스 변형에 쓰는가.
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 기능 전체의 토대가 되는 진입점이다.