我正在使用 Java Agent 和 Javassist 向某些 JDK 类添加一些日志记录。本质上,当系统加载一些 TLS 类时,Javassist 会向它们添加一些额外的字节码,以帮助我调试一些连接问题。
考虑到此类包含在代理 jar 中,问题如下:
package com.something.myagent;
public class MyAgentPrinter {
public static final void sayHello() {
System.out.println("Hello!");
}
}
在我的代理的转换方法中,假设我尝试使用 javassist 调用该类:
// this is only called for sun.security.ssl.Handshaker
ClassPool cp = getClassPool(classfileBuffer, className);
CtClass cc = cp.get(className);
CtMethod declaredMethod = cc.getDeclaredMethod("calculateKeys");
declaredMethod.insertAfter("com.something.myagent.MyAgentPrinter.sayHello();");
cc.freeze();
return cc.toBytecode();
你认为这会起作用,但我得到的是:
java.lang.NoClassDefFoundError: com/something/myagent/MyAgentPrinter
at sun.security.ssl.Handshaker.printLogLine(Handshaker.java)
at sun.security.ssl.Handshaker.calculateKeys(Handshaker.java:1160)
at sun.security.ssl.ServerHandshaker.processMessage(ServerHandshaker.java:292)
有什么方法可以添加该类[MyAgentPrinter
] 到应用程序的类路径?
您的代理的 jar 文件已添加到类路径中,如指定的那样the java.lang.instrument包文档 https://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html#package.description:
代理类将由系统类加载器加载(请参阅ClassLoader.getSystemClassLoader https://docs.oracle.com/javase/8/docs/api/java/lang/ClassLoader.html#getSystemClassLoader--)。这是类加载器,通常加载包含应用程序的类main
方法。这premain
方法将在与应用程序相同的安全性和类加载器规则下运行main
method.
这就是为什么 Javassist 在转换字节码时可以找到 Agent 的类的原因。
问题似乎是你正在改变一个sun.**
可能由引导加载程序或扩展加载程序加载的类。标准类加载委托是
application loader → extension loader → bootstrap loader
,因此应用程序加载器可用的类不可用于扩展或引导加载器加载的类。
因此,为了使它们可供所有类使用,您必须将代理的类添加到引导加载程序:
public class MyAgent {
public static void premain(String agentArgs, Instrumentation inst) throws IOException {
JarURLConnection connection = (JarURLConnection)
MyAgent.class.getResource("MyAgent.class").openConnection();
inst.appendToBootstrapClassLoaderSearch(connection.getJarFile());
// proceed
}
}
在任何其他操作之前执行此操作至关重要,即在加载要供检测代码使用的类之前。这意味着 Agent 类本身,即包含premain
方法无法被检测代码访问。 Agent 类也不应该直接引用MyAgentPrinter
以避免意外的提前加载。
更可靠的方法是添加Boot-Class-Path
Agent jar 清单的条目,请参阅包文档的“清单属性”部分 https://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html#navbar.bottom,以便在代理启动之前添加条目。但是,jar 文件的名称此后不得更改。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)