我有一些代码尝试在运行时使用
ClassFileTransformer
和 Instrumentation
的实例重新定义类。
但是,我注意到 transform
的 ClassFileTransformer
方法无法抛出任何异常。
这是一个示例(在 java 8 和 17 中测试):
import net.bytebuddy.agent.ByteBuddyAgent;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
public class Main {
public static void main(String[] args) {
// implementation 'net.bytebuddy:byte-buddy-agent:1.14.13'
ByteBuddyAgent.install();
Instrumentation instrumentation = ByteBuddyAgent.getInstrumentation();
instrumentation.addTransformer(new Transformer(), true);
try {
instrumentation.retransformClasses(Klass.class);
}catch (Exception e) {
System.out.println("An error occurred: " + e.getMessage());
return;
}
System.out.println("Finished successfully");
}
private static class Transformer implements ClassFileTransformer {
@Override
public byte[] transform(ClassLoader cl, String name, Class<?> klass, ProtectionDomain pd, byte[] classfileBuffer) {
System.out.println("Transforming class " + klass.getName());
throw new RuntimeException("Example exception");
}
}
private static class Klass {}
}
此代码抛出异常,并且逻辑上应该触发“发生错误:”消息。
相反,catch 块没有捕获任何异常:
Transforming class Main$Klass
Finished successfully
您知道是什么原因导致这种行为以及是否可以避免吗?
用户Slaw评论时是对的:
:“如果变压器抛出异常(它没有捕获),后续变压器仍将被调用,并且仍将尝试加载、重新定义或重新转换。因此,抛出异常具有相同的效果返回 null 的效果。”ClassFileTransformer
此提示归功于他/她。不过,我想添加一些细节:
只需打印堆栈跟踪(或对其进行调试)即可查看如何调用您的
transform
方法:
private static class Transformer implements ClassFileTransformer {
@Override
public byte[] transform(ClassLoader cl, String name, Class<?> klass, ProtectionDomain pd, byte[] classfileBuffer) {
System.out.println("Transforming class " + klass.getName());
new RuntimeException("Example exception").printStackTrace(System.out);
throw new RuntimeException("Example exception");
}
}
JDK 21 的控制台日志:
Transforming class Main$Klass
java.lang.RuntimeException: Example exception
at Main$Transformer.transform(Main.java:27)
at java.instrument/java.lang.instrument.ClassFileTransformer.transform(ClassFileTransformer.java:244)
at java.instrument/sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at java.instrument/sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:610)
at java.instrument/sun.instrument.InstrumentationImpl.retransformClasses0(Native Method)
at java.instrument/sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:225)
at Main.main(Main.java:14)
Finished successfully
TransformerManager
,找到代码中故意吞掉异常的位置(空白稍微重新格式化):
try {
transformedBytes = transformer.transform(module, loader, classname, classBeingRedefined, protectionDomain, bufferToUse);
}
catch (Throwable t) {
// don't let any one transformer mess it up for the others.
// This is where we need to put some logging. What should go here? FIXME
}