바이트코드 조작 ①에서는 바이트코드 조작 코드와 출력 코드를 같이 사용하게 되면 Rabbit
문자열이 출력되지 않았다.
이번 시간에는 바이트코드 조작 코드와 출력 코드를 동시에 실행시켜도 Rabbit
문자열이 출력 가능하게 해보자
public class Masulsa {
public static void main(String[] args) {
ClassLoader classLoader = Masulsa.class.getClassLoader();
TypePool typePool = TypePool.Default.of(classLoader);
try {
new ByteBuddy().redefine(
typePool.describe("me.whiteship.moja.Moja").resolve(),
ClassFileLocator.ForClassLoader.of(classLoader))
.method(named("pullOut")).intercept(FixedValue.value("Rabbit"))
.make().saveIn(new File("/Users/Hong/Desktop/java 8/HongJungWan-Java8-Java/target/classes/"));
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(new Moja().pullOut());
}
}
// 출력 Rabbit
바이트코드 조작 코드와 출력 코드를 동시에 실행시켜도 Rabbit
문자열이 출력 가능하다.
하지만 위 방법은 클래스 로딩 순서에 너무 의존적이라 다른 코드에서 Moja Class를 먼저 읽을 경우 의도대로 동작하지 않을 수 있다.
클래스 로더가 클래스를 읽어올 때 javaagent를 거쳐서,
변경된 바이트코드를 읽어서 사용하는 방법으로 접근해 보자
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.10.1</version>
</dependency>
Byte Buddy 의존성을 추가하자.
<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.whiteship.MasulsaAgent</Premain-Class>
<Can-Redefine-Classes>true</Can-Redefine-Classes>
<Can-Retransform-Classes>true</Can-Retransform-Classes>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
Agent 클래스를 사용하기 위해 jar 파일 안에다가 특정한 값들을 넣어줘야 한다.
그러기 위해 Manifest를 조작할 수 있는 maven-jar-plugin을 플러그인에 추가하자.
public class MasulsaAgent {
public static void premain(String agentArgs, Instrumentation inst) {
new AgentBuilder.Default()
.type(ElementMatchers.any())
.transform((builder, typeDescription, classLoader, javaModule) ->
builder.method(named("pullOut")).intercept(FixedValue.value("Rabbit"))).installOn(inst);
}
}
premain
mvn clean package
public class Masulsa {
public static void main(String[] args) {
System.out.println(new Moja().pullOut());
}
}
클래스 로더가 클래스를 읽어올 때 javaagent를 거쳐 변경된 바이트코드를 읽어온 결과 Rabbit
문자열이 정상 출력된다.