【发布时间】:2017-03-28 04:31:03
【问题描述】:
我正在尝试打印出 java 程序中使用的所有方法。为此,我创建了一个 java 代理,它使用检测来打印出每个调用的方法。该代理适用于简单的 HelloWorld 类型的程序,但在尝试将其用于更复杂的程序时却失败了。我不知道是什么导致它失败。
代码
(取自appcrawler并稍作修改):
agent.jar 源码:
SimpleTransformer.java:
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);
}
}
SimpleMain.java:
package test;
import java.lang.instrument.Instrumentation;
public class SimpleMain {
public static void premain(String agentArguments, Instrumentation instrumentation) {
instrumentation.addTransformer(new SimpleTransformer());
}
}
清单.mf:
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 错误。
【问题讨论】:
-
可能和这个问题有关bugs.openjdk.java.net/browse/JDK-8041920 - 你用的是什么Java?(具体信息如Oracle Java 8 121)
-
java.lang.invoke.CallSite 是一个抽象类参考:docs.oracle.com/javase/7/docs/api/java/lang/invoke/…。请检查您对抽象类的条件检查是否正常。
标签: java instrumentation javaagents