반응형
메이븐 JAR 플러그인 설정
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.2</version>
<configuration>
<archive>
<index>true</index>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
<manifestEntries>
<mode>development</mode>
<url>${project.url}</url>
<key>value</key>
<!-- 자바 에이전트 설정 -->
<Premain-Class>me.devhistory.MasulsaAgent</Premain-Class>
<Can-Redefine-Classes>true</Can-Redefine-Classes>
<Can-Retransform-Classes>true</Can-Retransform-Classes>
<!-- //자바 에이전트 설정 -->
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
Bytebuddy를 이용한 바이트 코드 조작(자바 에이전트)
public class MasulsaAgent {
public static void premain(String agentArgs, Instrumentation inst) {
new AgentBuilder.Default()
.type(ElementMatchers.any())
.transform(new AgentBuilder.Transformer() {
@Override
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule) {
return builder.method(named("pullOut")).intercept(FixedValue.value("Rabitt!"));
}
}).installOn(inst);
}
}
- Bytebuddy의 Agentbuilder를 사용하여 구현
- Agent를 jar로 패키징하여 jar 파일 안에다 자바 에이전트와 관련된 값을 넣어주어 동작 방식을 설정해야한다.
- 값은 maven jar plugin manifest 를 이용하여 빌드 옵션으로 추가할 수 있다.
- 값의 종류는 자바 에이전트 표준 문서의 Manifest Attributes 참고
우리가 구현한 것은 Premain
- Premain: 애플리케이션을 실행할 때 옵션을 줘서 에이전트 붙이는 방식
- Agent: 이미 프로세스에서 돌고 있는데 거기다 에이전트를 붙이는 방식
메이븐으로 패키징 하면 JAR에 있는 매니패스토 파일에 다음과 같이 자바 에이전트 관련 설정이 된 것을 확인할 수 있다. (Can-Redefine-Classes, Can-Retransform-Classes, Premain-Class)
Manifest-Version: 1.0
Created-By: Maven Archiver 3.4.0
Build-Jdk-Spec: 14
Class-Path: byte-buddy-1.11.0.jar
Can-Redefine-Classes: true
Can-Retransform-Classes: true
Premain-Class: me.devhistory.MasulsaAgent
key: value
mode: development
url:
자바 에이전트를 패키징 하여 jar를 만들었다면 사용해보자.
우측 상단의 Edit Configurations 를 클릭하여 창을 띄우고 Modify options를 클릭하여 Add VM options을 누른다. 그리고 VM options으로 "-javaagent:패키징한 jar 경로" 를 입력한다.
- 예) javaagent:F:\all_workspace\the_java_workspace\MasulsaJavaAgent\target\MasulsaAgent-1.0-SNAPSHOT.jar
자바 에이전트는 클래스 로딩 때 동작하게 되며 Masulsa 클래스에서 호출한 pullOut 메소드는 자바 에이전트를 거쳐서 변경된 바이트 코드를 읽어서 보여준다.
- 자바 에이전트 방식은 파일시스템의 .class 파일을 건드리지 않고 바이트 코드를 조작한다.(.class 파일이 변경되지 않고 메모리가 변경된다.)
- .class 파일을 파일 시스템에서 직접 조작하는 것과 달리 비침투적(Transparent)이다.(기존 코드를 건드리지 않는다.)
Moja.class
public class Moja {
public Moja() {
}
public String pullOut() {
return "";
}
}
public class Masulsa {
public Masulsa() {
}
public static void main(String[] args) {
System.out.println((new Moja()).pullOut()); //Rabbit!
}
}
Moja.class의 pullOut 메소드에서 반환되는 문자열은 없다. 하지만 Masulsa에서 호출한 pullOut 메소드는 자바 에이전트에서 바이트 코드를 조작한 결과인 Rabbit!를 출력하고 있다.
[참고자료]
반응형
'Java > 기본' 카테고리의 다른 글
자바 리플렉션(Java Reflection) API - 애노테이션 정보 조회 (0) | 2021.05.29 |
---|---|
자바 리플렉션(Java Reflection) API - 클래스 정보 조회 (0) | 2021.05.29 |
자바(Java) 바이트 코드 조작관련 - ByteBuddy (0) | 2021.05.27 |
자바(Java) 바이트 코드 조작관련 - 코드 커버리지 (0) | 2021.05.26 |
자바(Java) - 클래스 로더 시스템 구조 이해하기 (0) | 2021.05.25 |