3. Transformer와 Interceptor
전체 흐름
ProfilerPlugin.setup(...)
-> TransformTemplate.transform(...)
-> PluginInstrumentContext.addClassFileTransformer(...)
-> ClassFileTransformerLoader
-> MatchableClassFileTransformerDelegate
-> DefaultPluginContextLoadResult.getClassFileTransformer()
-> ClassFileTransformerProvider
-> DefaultClassFileTransformerDispatcher
-> JVM ClassFileTransformer.transform(...)
-> TransformCallback.doInTransform(...)
-> InstrumentMethod.addInterceptor(...)
-> instrumented method 실행 시 Interceptor.before/after 호출
3.1 Transformer 등록
파일:
agent-module/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/transformer/TransformTemplate.javaagent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/ClassFileTransformerLoader.javaagent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/ClassFileTransformerProvider.java
핵심 메소드:
TransformTemplate.transform(String, Class<? extends TransformCallback>)ClassFileTransformerLoader.addClassFileTransformer(...)ClassFileTransformerProvider.get()
plugin이 transformTemplate.transform("com.foo.Target", Callback.class)을 호출하면 내부적으로 class name matcher가 만들어지고 InstrumentContext.addClassFileTransformer(...)로 등록된다.
TransformTemplate.transform(...)
-> Matchers.newClassNameMatcher(className)
-> TransformCallbackChecker.validate(...)
-> instrumentContext.addClassFileTransformer(matcher, transformCallbackName)
-> ClassFileTransformerLoader.addClassFileTransformer(...)
-> new MatchableClassFileTransformerDelegate(...)
ClassFileTransformerProvider.get()는 plugin setup 결과에서 MatchableClassFileTransformer만 뽑아 TransformerRegistry로 만든다.
get()
-> newLambdaClassFileResolver(...)
-> newTransformerRegistry()
-> getMatchableTransformers(pluginContextLoadResult)
-> newDefaultTransformerRegistry(...)
-> new DefaultClassFileTransformerDispatcher(...)
DefaultApplicationContext는 이 dispatcher를 JVM에 등록한다.
instrumentation.addTransformer(classFileTransformer, true)
3.2 JVM transform 시점
파일:
agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/transformer/DefaultClassFileTransformerDispatcher.javaagent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/transformer/DefaultTransformerRegistry.javaagent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/transformer/MatchableTransformerRegistry.javaagent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/MatchableClassFileTransformerDelegate.java
핵심 메소드:
DefaultClassFileTransformerDispatcher.transform(...)TransformerRegistry.findTransformer(...)MatchableClassFileTransformerDelegate.transform(...)
JVM이 클래스를 로딩하거나 재변환할 때 dispatcher의 transform(...)이 호출된다.
DefaultClassFileTransformerDispatcher.transform(...)
-> classLoaderFilter.accept(...)
-> lambdaClassFileResolver.resolve(...)
-> pinpointClassFilter.accept(...)
-> dynamicTransformerRegistry.getTransformer(...)
-> unmodifiableFilter.accept(...)
-> transformerRegistry.findTransformer(...)
-> baseClassFileTransformer.transform(..., transformer)
일반 plugin transformer는 transformerRegistry.findTransformer(...)에서 찾아진다.
DefaultTransformerRegistry: class name 기반 matcher를 map lookup으로 찾는다.MatchableTransformerRegistry: class/package 기반 index와 class metadata matcher를 사용한다.
찾은 transformer가 MatchableClassFileTransformerDelegate이면, 여기서 plugin의 TransformCallback이 실행된다.
MatchableClassFileTransformerDelegate.transform(...)
-> new GuardInstrumentor(...)
-> transformCallbackProvider.getTransformCallback(...)
-> transformCallback.doInTransform(...)
-> guard.close()
3.3 Interceptor 삽입 예시: Jackson plugin
파일:
agent-module/plugins/jackson/src/main/java/com/navercorp/pinpoint/plugin/jackson/JacksonPlugin.javaagent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMMethod.java
JacksonPlugin.setup(...)은 ObjectMapper, ObjectReader, ObjectWriter에 transformer를 등록한다.
JacksonPlugin.setup(...)
-> addObjectMapperEditor("com.fasterxml.jackson.databind.ObjectMapper")
-> transformTemplate.transform(clazzName, ObjectMapperTransform.class)
ObjectMapperTransform.doInTransform(...)은 대상 class를 InstrumentClass로 읽고, method/constructor에 interceptor를 붙인다.
doInTransform(...)
-> instrumentor.getInstrumentClass(...)
-> target.getConstructor(...)
-> target.getDeclaredMethods(MethodFilters.name(...))
-> method.addInterceptor(...)
-> target.toBytecode()
ASMMethod.addInterceptor(...)는 interceptor 객체를 만들고 method bytecode에 before/after 호출 코드를 삽입한다.
ASMMethod.addInterceptor(...)
-> newInterceptor(...)
-> createInterceptor(...)
-> addInterceptor0(...)
-> createInterceptorDefinition(...)
-> before/after interceptor bytecode 삽입
실무에서 새 plugin을 만들 때는 대개 이 세 단계만 기억하면 된다.
1. setup()에서 대상 클래스 등록
2. TransformCallback에서 대상 메소드 선택
3. addInterceptor() 후 target.toBytecode()'개발 메모' 카테고리의 다른 글
| Pinpoint 분석 #7 (0) | 2026.08.04 |
|---|---|
| Pinpoint 분석 #6 (0) | 2026.08.04 |
| Pinpoint 분석 #4 (0) | 2026.08.04 |
| Pinpoint 분석 #3 (0) | 2026.08.04 |
| Pinpoint 분석 #2 (0) | 2026.08.04 |