스프링 AOP

Java Agent

GLaDiDos 2024. 9. 4. 09:24

https://sundaland.tistory.com/78

 

[ ▶ Java Agent ]

자바 에이전트는 자바 애플리케이션의 실행 중 동작을 변경하거나 모니터링할 수 있는 특별한 프로그램이다. 자바 에이전트는 JVM (자바 가상 머신)과 상호 작용하여 클래스 로딩 시점에 바이트코드를 조작하거나, 이미 로드된 클래스의 동작을런타임에 수정할 수 있다. 이러한 기능은 성능 모니터링, 디버깅, 프로파일링, 코드 커버리지 분석, 그리고 AOP (Aspect-Oriented Programming) 구현 등 다양한 목적에 사용된다.

 

[ ▷ 자바 에이전트의 주요 특징 ]

1. Permain 메서드

  • 자바 에이전트는 JVM이 시작될 때 premain 메서드를 통해 실행된다. 이 메서드는 JVM이 메인 애플리케이션을 실행하기 전에 호출된다.
  • premain 메서드는 두 가지 형태로 아래와 같이 정의된다. 
  • public static void premain(String agentArgs, Instrumentation inst)
  • public static void premain(String agentArgs)

2. Instrumentation API 사용

  • 자바 에이전트는 Instrumentation API를 통해 클래스 로딩 과정에 개입할 수 있다. 이 API는 바이트코드를 변환하거나, 재정의할 수 있는 메서드들을 제공하며, 이를 통해 자바 에이전트는 런타임에 애플리케이션의 동작을 변경할 수 있다.
  • 주요 메서드로는 클래스 로딩 시 바이트코드로 변환되는 addTransformer와 이미 로드된 클래스를 재정의 하는 redefineClasses 등이 있다. 

3. 자바 에이전트 등록 및 실행

  • 자바 에이전트는 JVM 시작 시 -javaagent 옵션을 통해 등록된다.
  • 예를 들어, -javaagent:/path/to/agent.jar -jar myapp.jar 같은 형식이다.
  • 이 옵션은 JVM이 시작될때 지정된 JAR 파일을 자바 에이전트로 인식하고, 해당 에이전트의 permain 메서드를 호출한다.

4. JAR 파일 구조

  • 자바 에이전트는 JAR 파일 형태로 패키징되며, META-INF/MANIFEST.MF 파일에 Premain-Class라는 속성이 포함되어야하다. 이 속성은 JVM에 어떠 클래스의 permain 메서드를 호출할지를 지정하나.
  • 예를 들어, Permain-Class: com.example.MyAgent 같은 형식이다.

 

[ ▷ 자바 에이전트의 일반적인 사용 사례 ]

1. 성능 모니터링

  • 애플리케이션의 실행중 성능 관련 데이터를 수집하기 위해 자바 에이전트를사용하여 메서드 실행 시간, 메모리사용량 등 을 추적할 수 있다.

2. 프로파일링 도구

  • 자바 에이전트는 애플리케이션의 실행을 프로파일링하는 도구로 사용되어, 실행 중인 애플리케이션의메모리 사용, 스레드 상태, CPU 사용 등을 분석할 수 있다.

3. 코드 커버리지 분석

  • 자바 에이전트는 테스트 실행 중 어떤 코드가 실행되었는지를 추적하여 코드 커버리지 정보를 수집하고, 이를 바탕으로 커버리지 보고서를 생성할 수 있다.

4. AOP(Aspect-Oriented Programming)

  • AspectJ와 같은 AOP 프레임워크에서 자바 에이전트를 사용하여 런타임에 클래스 파일을 변환하고, 특정 메서드 호출 전후에 코드를 삽입하는 등의 기능을 구혀할 수 있다.

5. 디버깅 및 로깅

  • 자바 에이전트를 사용하여 애플리케이션의 실행 중 특정 이벤트나 상태를 실시간으로 로깅하거나, 디버깅 정보를 수집할 수 있다.

 

[ ▷ 자바 에이전트의 예시 코드 ]

▼ 모든 클래스가 로드될 때마다 그 클래스의 이름을 출력하는 자바 에이전트

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;

public class SimpleAgent {
    public static void premain(String agentArgs, Instrumentation inst) {
        inst.addTransformer(new SimpleTransformer());
    }
}

class SimpleTransformer implements ClassFileTransformer {
    @Override
    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, 
                            ProtectionDomain protectionDomain, byte[] classfileBuffer) {
        System.out.println("Transforming class: " + className);
        // 바이트코드를 수정하지 않는 경우 원본 바이트코드를 반환
        return classfileBuffer;
    }
}

자바 에이전트는 JVM의 클래스 로딩 과정에 개입하여 애플리케이션의 동작을 실시간으로 조작할 수 있는 도구이다. 주로 Instrumentation API를 사용하여 바이트코드 수준에서의 수정 작업을 수행하며, 성능 모니터링, 프로파일링, 코드 커버리지 분석, AOP 구현 등 다양한 용도로 사용되다. 자바 에이전트는 JVM 시작 시 -javaagent 옵션을 통해 로드되며, 애플리케이션의 실행 전바에 걸쳐 중요한 역할을 할 수 있다.


[ ▷ 자바 에이전트의 종류 ]

대표적인 자바 에이전트들은 다양한 목적에 맞춰 개발된 도구들로, 주로 성능 모니터링, 프로파일링, 코드 커버리지 분석, AOP 구현 등을 위해 사용된다.

 

1. 자바 Flight Recorder (JFR)

  • 용도: 성능 모니터링 및 프로파일링
  • 설명:  JFR은 JDK에 내장된 성능 모니터링 도구로, 자바 애플리케이션의 실행 중 발생하는 다양한 이벤트를 기록하고 분석하는데 사용된다. JFR은 매우 낮은 오버헤드로 성능 데이터를 수집할 수 있어, 프로덕션 환경에서 성능 문제를 분석하는데 매우 유용하다.
  • 특징: JFR은 JDK에 내장되어 있으며, 별도의 설치가 필요하지 않고, -XX:StartFlightRecording 옵션으로 활성화할 수 있다.

2. JaCoCo (Java Code Coverage Library)

  • 용도: 코드 커버리지 분석
  • 설명: JaCoCo는 자바 애플리케이션의 테스트 커버리지를 측정하기 위한 도구이다. JaCoCo의 자바 에이전트는 테스트 실행 중 어떤 코드가 실행되었는지를 추적하여, 코드 커버리지 보고서를 생성한다.
  • 특징: Maven, Gradle 등 빌드 도구와 쉽게 통합되며, CI/CD 파이프라이엔서 코드 커버리지를 자동으로 측정하고 보고할 수 있다.

3. New Relic

  • 용도: 애플리케이션 성능 모니터링
  • 설명: New Relic은 클라우드 기반의 애플리케이션 성능 모니터링 도구로, 자바 에이전트를 통해 애플리케이션의 성능을 모니터링하고 문제를 진단할 수 있다. New Relic의 자바 에이전트는 메서드 호출, 데이터베이스 쿼리, 외부 API 호출 등을 모니터링하여 실시간 성능 데이터를 수집한다.
  • 특징: 다양한 대시보드와 실시간 성능 모니터링 기능을 제공하며, 클라우드 서비스와 통합이 용이하다.

4. AspectJ

  • 용도:  AOP (Aspect-Oriented Programming)
  • 설명: AspectJ는 자바에서 AOP를 구현하는 프레임워크로, 자바 에이전트를 통해 런타임에 클래스 파일을 위빙 (Weaving)할 수 있다. 이를 통해 특정 포인트컷에 따라 메서드 호출 전후에 코드를 삽입하는 등의 작업을 수행할 수 있다.
  • 특징: 로드 타임 위빙 (LTW)을 지원하며, 복잡한 비즈니스 로직에서 횡단 관심사를 분리하여 관리할 수 있다.

5. Byte Buddy

  • 용도: 런타임 바이트코드 조작
  • 설명: Byte Buddy는 자바 클래스의 바이트코드를 런타임에 동적으로 생성하거나 변환하는 라이브러리이다. 자바 에이전트를 통해 클래스 로딩 시점에서 바이트코드를 변환하는 작업을 쉽게 수행할 수 있다.
  • 특징: 다양한 프레임워크와 통합이 용이하며, 바이트코드를 조작하는데 필요한 강력한 API를 제공한다.

6. BTrace

  • 용도: 런타임 디버깅 및 트레이싱
  • 설명: BTrace는 자바 애플리케이션의 런타임 동작을 실시간으로 추적할 수 있는 도구이다. BTrace의 자바 에이전트는 애플리케이션 코드의 변경 없이 다양한 이벤트를 실시간을 추적할 수 있다.
  • 특징: 매우 가볍고, 애플리케이션의 성능에 최소한의 영향을 주며, 실시간 모니터링에 적합하다.

7. Glowroot

  • 용도: 애플리케이션 성능 모니터링 (APM)
  • 설명:  Glowroot는 오픈 소스 APM 도구로, 자바 에이전트를 통해 애플리케이션의 성능을 모니터링한다. Glowroot는 스레드 프로파일링, 트랜잭션 추적, SQL 분석 등 다양한 기능을 제공한다.
  • 특징: 설치와 설정이 간편하며, 경량화된 APM 솔루션으로 많은 개발자와 팀에서 애용된다.

자바 에이전트는 JVM에서 실행되는 자바 애플리케이션의 동작을 실시간으로 모니터링하거나 수정할 수 있는 매우 강력한 도구이다. 위에서 소개한 대표적인 자바 에이전트들은 각각 다른 목적에 맞게 설계되어 있으며, 성능 모니터링, 코드 커버리지 분석, AOP 구현, 디버깅 등 다양한 작업을 수행할 수 있다.


위의 자바 에이전트 코드는 JVM이 시작될 때 로드되며, 모든 클래스가 로드될 때마다 해당 클래스의 이름을 출력하고, 바이트코드를 수정하지 않고 원본 그래도 반환하는 간단한 자바 에이전트이다.

[ ▶ 자바 에이전트 사용 방법 ]

[ ▷ Java Agent 컴파일 및 JAR 파일 생성 ]

위의 자바 에이전트 코드를 컴파일하고, JAR 파일로 패키징해야 한다. JAR 파일에는 META-INF/MANIFEST.MF 파일에 Premain-Class 속성을 설정해야 한다.

1.  SimpleAgent.java 파일로 저장

위의 코드를 SilmeAgent.java 파일로 저장한다.

2. 컴파일

javac SimpleAgent.java

3. JAR 파일 생성

JAR 파일을 생성할 때, META-INF/MANIFEST.MF 파일에 Premain-Class를 지정한다.

Premain-Class: SimpleAgent

▼ JAR 파일 생성 명령

jar cmf MANIFEST.MF simple-agent.jar SimpleAgent.class SimpleTransformer.class

 

[ ▷ 자바 에이전트를 사용하는 애플리케이션 실행 ]

이제 생성된 자바 에이전트 JAR 파일 (simple-agent.jar)을 애플리케이션과 함께 실행한다.

아래는 자바 에이전트를 사용하는 애플리케이션의 실행 예제이다.

1. 간단한 자바 애플리케이션 작성

public class MyApplication {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

이 코드를 MyApplication.java로 저장하고 컴파일한다.

javac MyApplication.java

 

2. 자바 에이전트와 함께 애플리케이션 실행

자바 에이전트를 사용하려면 -javaagent 옵션을 사용하여 JVM을 실행할 때 에이전트를 로드한다.

java -javaagent:/path/to/simple-agent.jar -cp . MyApplication

 

[ ▷ 실행 결과 ]

애플리케이션이 실행될 때, SimpleAgent가 로드되고, MyApplication 클래스를 포함한 모든 클래스가 로드될 때마다 클래스 이름이 출력된다.

Transforming class: MyApplication
Hello, World!

 

[ ▷ 요약 ]

  1. SimpleAgent.java 코드를 컴파일하고 JAR 파일로 패키징한다.
  2. -javaagent 옵션을 사용하여 자바 에이전트 JAR 파일을 로드하고 애플리케이션을 실행한다.
  3. 애플리케이션이 실행되는 동안 로드되는 모든 클래스 이름이 출력된다.

이 예제는 자바 에이전트의 기본적인 사용 방법을 보여주며, 실제 애플리케이션에서 다양한 목적을 위해 바이트코드 조작을 적용할 수 있다.