Java插装:防止类引用加载类

Java插装:防止类引用加载类,java,instrumentation,javaagents,java-reflection,Java,Instrumentation,Javaagents,Java Reflection,大家好,我的社区 我最近发现了Java插装,以及可以用它做什么伟大的事情,所以我决定为自己编写一个小型库,简化其中的一些事情 我有以下方法(简化): publicstaticvoideditclass(类clazz){ ... } 它通过工具添加了一个转换器,该工具转换名为clazz.getName()的加载类的字节码 所以在我的premain方法中,我可以说 editClass(Foo.class); 我的问题是,通过对类(.class)的引用来指定该类,该类在添加转换器之前被加载,因此在

大家好,我的社区

我最近发现了Java插装,以及可以用它做什么伟大的事情,所以我决定为自己编写一个小型库,简化其中的一些事情

我有以下方法(简化):

publicstaticvoideditclass(类clazz){
...
}
它通过工具添加了一个转换器,该工具转换名为
clazz.getName()
的加载类的字节码

所以在我的premain方法中,我可以说

editClass(Foo.class);
我的问题是,通过对类(.class)的引用来指定该类,该类在添加转换器之前被加载,因此在此之后,我必须重新转换该类,这会阻止我添加/删除方法等等

那么,有没有一种方法在使用这个类引用时不加载该类?还是用另一种方法来实现这一点?我知道我可以将类名作为参数传递,但我真的希望使整个库类型安全并使重构更容易


提前谢谢

如果您只想从
premain
调用
editClass
方法,并且我们假设Java代理本身不使用该类,因此
editClass
调用中的类文本将是唯一的触发器,您可以执行以下操作:

  • 提供两种方法,
    editClass(Class clazz)
    editClass(String qualifiedName)
  • 使用
    editClass(Class)
    编写
    premain
    方法(或一般的代理类),并享受编译时通过文本引用的类的安全性
  • 执行代理类的静态代码转换,用
    editClass(String)
    替换所有调用
    editClass(Class)
    这应该不会太难,因为您只需将
    ldc packagename/Foo.class
    invokestatic(Ljava/lang/class;)V
    的所有序列替换为
    ldc“packagename.Foo”
    invokestatic(Ljava/lang/String;)V

    如果方法
    editClass(String qualifiedName)
    可以处理内部类名(使用斜杠而不是点),则可能会变得更简单。
    既然您说您“最近发现了Java工具”,这可能是类文件转换中的一个很好的练习
  • 使用已转换的代理类(不再引用要转换的类)执行加载时转换

考虑到Spring Boot专门对类文件进行字节码分析,以便能够使用类文本作为注释参数,我很确定没有办法进行内联分析。谁是第一个,是鸡还是蛋?在引用(并因此解析)类之前,不能在转换类的同时引用它。要么使用类名字符串,要么必须接受重传所涉及的限制,例如您描述的限制。这里没有魔杖。也许如果你的类处于薛定谔猫那样的量子态,同时加载和不加载,你可以设计一个方案来实现这一点。您希望使操作类型安全,这意味着
editClass
方法的调用方无论如何都会使用
Foo
类,因此控制加载时间的尝试注定会失败(或以非常脆弱的代码告终)。链接或验证调用类时,可以加载
Foo
类。