开始研究Java Bytecode Instrumentation。
和往常一样,Hello World就是我的开始。
短版:我构建了一个打印Hello World
的项目,我现在想要修改该类,以便打印Hello ASM
。为此,我实现了一个虚拟代理,我后来打算对其进行修改,以便进行必要的更改。如何修改build.gradle
文件以便我可以使用/测试它?
[编辑:git clone https://bitbucket.org/RKor/helloasm.git
]
长版:
package helloasm;
import helloasm.instrumentation_targets.HelloWorld;
public class Main {
public static void main(String[] args) {
new HelloWorld().doSomething();
}
}
,其中
package helloasm.instrumentation_targets;
public class HelloWorld {
public String doSomething(){
String output = "Hello World";
System.out.println(output);
return output;
}
}
我让它返回输出字符串,这样我们就可以在JUnit中将它与一个简单的测试用例
进行比较package helloasm.instrumentation_targets;
import org.junit.Test;
import static org.junit.Assert.*;
public class HelloWorldTest {
@Test
public void doSomething() throws Exception {
assertEquals("Hello ASM",new HelloWorld().doSomething());
}
}
现在显然,测试将失败,程序将固执地打印Hello World
。让我们改变它。
Java字节码检测需要以.jar
格式提供代理。
当我使用Intellij时,我创建了一个新模块," HelloWorldAgent",并且在其 build.gradle
文件中,我添加了
implementation "org.ow2.asm:asm:5.2"
作为依赖。
现在我们添加一个代理
package helloasm.agents
import java.lang.instrument.Instrumentation;
public class Agent {
public static void premain(String args, Instrumentation instrumentation){
HelloWorldInterceptor transformer = new HelloWorldInterceptor();
instrumentation.addTransformer(transformer);
}
}
和变压器
package helloasm.agents
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
public class HelloWorldInterceptor implements ClassFileTransformer{
@Override
public byte[] transform(
ClassLoader loader,
String className,
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer
) throws IllegalClassFormatException {
System.out.println(className + " loaded");
return classfileBuffer;
}
}
还没有做任何令人兴奋的事情,但我想在继续之前先让它全部运行。
我们添加到子模块build.gradle
:
jar {
archiveName = "${rootProject.name}-${rootProject.version}-agent.jar"
manifest {
attributes(
'Premain-Class': 'ch.ethz.koradir.helloasm.agents.Agent',
'Can-Redefine-Classes': 'true',
'Can-Retransform-Classes': 'true',
'Can-Set-Native-Method-Prefix': 'true',
'Implementation-Title': "HelloWorldInterceptor",
'Implementation-Version': rootProject.version
)
}
}
现在怎样?回到根项目的build.gradle
,我需要以某种方式指定
HelloWorldAgent
编译到jar,首先是-javaagents
标志,提供jar 我该怎么做?
答案 0 :(得分:1)
settings.gradle
HelloWorldAgent
文件
include 'HelloWorldAgent'
添加到根settings.gradle
文件rootProject
中的三个HelloWorldAgent/build.gradle
更改为project
build.gradle
evaluationDependsOn 'HelloWorldAgent'
test {
def jarTask = project('HelloWorldAgent').tasks.jar
dependsOn jarTask
afterEvaluate {
jvmArgs "-javaagent:$jarTask.archivePath"
}
}
您的测试仍然会失败,但您会看到变压器的输出。