我试图打印出java程序中使用的所有方法。为此,我创建了一个java代理,它使用检测来打印出每个被调用的方法。该代理适用于简单的HelloWorld类型程序,但在尝试在更复杂的程序上使用时失败。我不知道是什么导致它失败。
(取自appcrawler并稍作修改):
agent.jar源代码:
package test;
import java.security.*;
import java.lang.instrument.*;
import java.util.*;
import javassist.*;
public class SimpleTransformer implements ClassFileTransformer {
public SimpleTransformer() {
super();
}
public byte[] transform(ClassLoader loader, String className, Class redefiningClass, ProtectionDomain domain, byte[] bytes) throws IllegalClassFormatException {
return transformClass(redefiningClass,bytes);
}
private byte[] transformClass(Class classToTransform, byte[] b) {
ClassPool pool = ClassPool.getDefault();
CtClass cl = null;
try {
cl = pool.makeClass(new java.io.ByteArrayInputStream(b));
CtBehavior[] methods = cl.getDeclaredBehaviors();
for (int i = 0; i < methods.length; i++) {
if (methods[i].isEmpty() == false) {
changeMethod(methods[i]);
}
}
b = cl.toBytecode();
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (cl != null) {
cl.detach();
}
}
return b;
}
private void changeMethod(CtBehavior method) throws NotFoundException, CannotCompileException {
/*if (method.getName().equals("doIt")) {
method.insertBefore("System.out.println(\"started method at \" + new java.util.Date());");
method.insertAfter("System.out.println(\"ended method at \" + new java.util.Date());");
}*/
//MY CODE
//!Modifier.isAbstract(method.getModifiers()) -- abstract methods can't be modified. If you get exceptions, then add this to the if statement.
//native methods can't be modified.
if (!Modifier.isNative(method.getModifiers()) && !Modifier.isAbstract(method.getModifiers())) {
String insertString = "System.out.println(\"started method " + method.getName() + "\");";
method.insertBefore(insertString);
}
}
package test;
import java.lang.instrument.Instrumentation;
public class SimpleMain {
public static void premain(String agentArguments, Instrumentation instrumentation) {
instrumentation.addTransformer(new SimpleTransformer());
}
}
Manifest-Version: 1.0
Boot-Class-Path: javassist.jar
Premain-Class: test.SimpleMain
Exception in thread "main"
java.lang.BootstrapMethodError: java.lang.NoClassDefFoundError: Could not initialize class java.lang.invoke.CallSite
at sun.net.www.protocol.http.HttpURLConnection.getNetProperty(Unknown So
urce)
at sun.net.www.protocol.http.HttpURLConnection.<clinit>(Unknown Source)
at sun.net.www.protocol.http.Handler.openConnection(Unknown Source)
at sun.net.www.protocol.http.Handler.openConnection(Unknown Source)
at java.net.URL.openConnection(Unknown Source)
at java.net.URL.openStream(Unknown Source)
at io.ludi.myProgram.ConfigReader.readConfig(ConfigReader.java:41)
at io.ludi.myProgram.ConfigReader.read(ConfigReader.java:68)
at io.ludi.myProgram.App.main(App.java:23)
Caused by: java.lang.NoClassDefFoundError: Could not initialize class java.lang.
invoke.CallSite
at java.lang.invoke.MethodHandleNatives.linkCallSiteImpl(Unknown Source)
at java.lang.invoke.MethodHandleNatives.linkCallSite(Unknown Source)
代码工作正常,没有附加java代理。我不明白为什么它会抛出ClassDefNotFound错误。
答案 0 :(得分:0)
找到以下解决方法。只是我在Agent Class中的premain()方法的开头用Class.forName(“ java.lang.invoke.CallSite”)加载了CallSite。在添加Transformer类之前已加载。
public class SimpleMain {
public static void premain(String agentArgs, Instrumentation inst) {
Class t = null;
try {
**t = Class.forName("java.lang.invoke.CallSite");**
} catch (Throwable e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
.
.
.
instrumentation.addTransformer(new MyTransformer());
}
}