关于ZAKER 融媒体解决方案 合作 加入

java – 如何在 asm 代码中正确使用 Instrumentation.retransformClasses ( ) ?

CocoaChina 11-17

我正在使用 asm 库来执行一些Java字节码修改 – 专门用于修改我的类以实现新的接口和相关方法 . 我目前的方法是通过 javaagent 使用核心 asm API. 我想保留这种动态方法 , 而不是静态修改 .class 文件 .

在更高的层次上 , 我的问题是 , 如果我选择修改从 B 扩展的 A 类 , 我还需要修改 B. ( 鉴于我对如何在 JVM 中加载类的理解 , 我相信 B 类将永远是在 A 级之前交给变压器 . ( 如果我错了 , 请纠正我 . ) 鉴于这个假设 , 我认为我需要返回并重新转换 B. 我的方法在这段代码中被捕获:

public byte [ ] transform ( ClassLoader l, String name, Class<?> clazz, ProtectionDomain d, byte [ ] b ) { throws IllegalClassFormatException { // **1** System.out.println ( "--->>> " + name ) ; if ( interestingClass ( name ) ) { try { ClassReader cr = new ClassReader ( b ) ; ClassWriter cw = new ClassWriter ( cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES ) ; PyClassVisitorAdapter pv = new PyClassVisitorAdapter ( cw, name ) ; cr.accept ( pv, 0 ) ; // **2** Retrieve the superclass and try to transform that if ( ! "Ljava/lang/Object;".equals ( pv.getSuperName ( ) ) ) { String cName = classJvmToCanonical ( pv.getSuperName ( ) ) ; Class [ ] classes = inst.getAllLoadedClasses ( ) ; for ( Class c : classes ) { if ( c.getName ( ) .equals ( cName ) ) { inst.retransformClasses ( c ) ; break; } } } // Dump the transformed class ClassReader cr2 = new ClassReader ( cw.toByteArray ( ) ) ; ClassWriter cw2 = new ClassWriter ( cr2, 0 ) ; TraceClassVisitor tcv = new TraceClassVisitor ( cw2, new PrintWriter ( System.out ) ) ; cr2.accept ( tcv, 0 ) ; return cw2.toByteArray ( ) ; } catch ( Exception ex ) { ex.printStackTrace ( ) ; return null; } } else { return b; }}

( inst 是 Instrumentation 的句柄 , 它在构造函数中传入 )

我正在努力的部分是 ** ** ** 注释中标记的块 . 让我们再说一次 A 扩展 B 并且我’感兴趣’转换 A. 我期待的是我会看到超类 ( B ) 的名称被打印在 ** 1 ** ( 但是没有被转换 , 因为我不认为它在第一次传球时很有意思 ) 然后 , 一旦我得到 ** 2 ** 并发现 A 的超类是 B, 我应该尝试重新转换 B. 此时我期待这种方法再次调用 ( 通过 inst.retransformClasses ( ) ) , 我会看到 B 打印在 ** 1 **. 但是 , 我没有 . ( 我已经添加了 print 语句 , 并确定我正在接收转换调用 . 我还检查过 Instrumentation.isRetransformClassesSupported ( ) 和 Instrumentation.isModifiableClass ( c ) 都返回 true ) .

我相信我已经正确设置了代理商 ; 在清单中将 Can-Retransform-Classes 和 Can-Redefine-Classes 设置为 true. 此外 , 当我在代理的 premain 方法中将变换器添加到 Instrumentation 时 , 我这样做:

public static void premain ( String agentArgs, Instrumentation inst ) { inst.addTransformer ( new PyClassFileTransformer ( inst ) , true ) ;}

关于我在这里做错了什么见解?谢谢 .

您可以更改字节码检测策略 , 因此在加载 B 类时 , 您会找到其所有子类 , 并在此时决定是否需要立即修改 B 类 . 这可以通过在内存中维护类元数据存储库或缓存 ( 即有关类层次结构的信息 ) 来优化 , 因此您不必每次都加载元数据 .

以上内容由"CocoaChina"上传发布 查看原文
相关标签 中将代码

觉得文章不错,微信扫描分享好友

扫码分享