Pinpoint 분석 #5

2026. 8. 4. 00:20·개발 메모

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.java
  • agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/ClassFileTransformerLoader.java
  • agent-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.java
  • agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/transformer/DefaultTransformerRegistry.java
  • agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/transformer/MatchableTransformerRegistry.java
  • agent-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.java
  • agent-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
'개발 메모' 카테고리의 다른 글
  • Pinpoint 분석 #7
  • Pinpoint 분석 #6
  • Pinpoint 분석 #4
  • Pinpoint 분석 #3
csb0710
csb0710
  • csb0710
    데모장
    csb0710
  • 전체
    오늘
    어제
    • 분류 전체보기 (60)
      • 스프링부트 메모 (7)
      • 개발 메모 (10)
      • 클라우드 메모 (10)
      • 설치&설정 메모 (2)
      • 알고리즘 메모 (18)
      • 인턴 메모 (7)
      • 데이터베이스 메모 (3)
      • 책 메모 (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    서버 연결
    티스토리챌린지
    GitHub
    오블완
    코드트리
    자동 답변 봇
    서버배포
    서버생성
    .gitmodules
    백준
    이지퍼블리싱
    코딩테스트
    HBase
    디비설치
    그리디
    디비설정
    submodule
    알고리즘
    스프링부트
    코드트리조별과제
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.2
csb0710
Pinpoint 분석 #5
상단으로

티스토리툴바