字节码注入发生在哪里? [英] Where does bytecode injection happen?

查看:32
本文介绍了字节码注入发生在哪里?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 SomeObject.java 文件:

class SomeObject {
   String name;
}

编译它会创建一个包含字节码的 SomeObject.class 文件.

Compiling it creates a bytecode-containing SomeObject.class file.

0xCAFEBABE...

如果我们在 JVM 上使用 SomeObject,它会被当前的类加载器加载并且一切正常.

If we use SomeObject on the JVM, it is loaded by the current classloader and all works fine.

现在让我们假设我想要一些动态代码生成.我可以编写我的自定义注释

Now let's assume that I'd like to have some dynamic code generation. I can write my custom annotation

@Target(ElementType.TYPE)
public @interface Data {
   ...
}

并将其作为修饰符添加到类声明中:

and add it as a modifier to the class declaration:

@Data
class SomeObject {
   String name;
}

我也可以使用 @Retention(RetentionPolicy.RUNTIME) 为运行时保留它:

I can also retain it for the runtime with @Retention(RetentionPolicy.RUNTIME):

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Data {
   ...
}

问题

用于字节码注入的注解在哪里?类加载器在加载具有适当运行时保留注释的类时是否会注入字节码,如下图所示:

Question

Where are annotations used for bytecode injection? Does a classloader inject bytecode when loading the class with the appropriate runtime retained annotation like in this figure:

source -(compile)-> bytecode -(classloader bytecode injection)-> injected bytecode -(classloading)-> JVM loaded bytecode   

推荐答案

是的,可以让您的自定义类加载器通过 JavassistASM 执行修改,加载到内存中的不是类文件中的字节码,而是修改后的字节码.尽管有更简单(在我看来更好)的方法.

Yes, it would be possible to have your custom classloader to load a class and through bytecode manipulation tools such as Javassist or ASM perform the modifications, loading into memory not the bytecode in the class file but rather the modified one. Although there are easier (and better, in my opinion) ways of doing it.

从 Java 6 开始,您拥有 APT它允许您挂钩到编译过程(通过 javac 中的 -processor 参数).使用 APT,您可以访问代码的 AST(抽象语法树),并且可以在使用 javax.lang.model.这意味着您的类文件将生成所需的修改.

Since Java 6 you have APT which allows you to hook into the compiling process (via -processor argument in javac). With APT you have access to the code's AST (Abstract Syntax Tree) and you can perform modifications directly when compiling using the javax.lang.model. This means that your class file will be generated with the needed modifications.

在这种情况下,链将类似于:

In this case the chain would be something like something like:

source -(在模型级别编译和执行修改)->字节码已修改 - 常规类加载器 ->将类加载到内存中

另一种可以使用的方法是在编译后执行字节码注入作为编译后过程.在这种情况下,您可以使用字节码修改工具(再次是 javassist、asm 等),当找到所需的注释时,它们可以执行您需要的修改,使用注入的字节码生成一个新的类文件.

Another approach which can be used is to perform bytecode injection after compilation as a post-compiling process. In this cases you use bytecode modification tools (once again javassist, asm, among others), which can perform the modifications you need when the desired annotation is found, generating a new class file with the injected bytecode.

在这种情况下,您的连锁店将是:

In such case your chain would be:

source -compile ->字节码-编译后->修改后的字节码 - 常规类加载器 ->将类加载到内存中

最后我们到达运行时字节码修改.即使您的想法是可能的,在我看来,我还是会离开类加载器 magic 并使用诸如 Javassist 之类的工具,这些工具也允许您拥有 动态代理 可以修改和重新加载.

Finally we reach runtime bytecode modifications. Even though your idea is possible, in my opinion I would leave the class loader magic and use tools such has Javassist that also allows you to have dynamic proxies which can be modified and reloaded.

在 javassist 的特殊情况下,链将是

In javassist particular case the chain would be

source -compile ->字节码-编译后->修改后的字节码 - 常规类加载器 ->加载到内存中 - javassist 代理 ->修改后的类 - javassist 热插拔器 ->重新修改的类

代理并不完美(好吧,什么都不是).您将受到性能影响,并且无法修改类的公共接口(旁注:APT 和编译后过程都可以允许您修改类的公共接口).我可以继续讨论这个问题,但我认为这些信息已经足够让您深思了.如果您需要更多信息,请随时发表评论.

Proxies aren't perfect though (well nothing is). You'll have a performance hit and you won't be able to modify the public interface of your class (sidenote: both APT and post-compile process can allow you to modify the class public interface). I could go on a bit more on this, but I think this is already enough information to give you food for thought. Feel free to leave a comment if you need additional information.

这篇关于字节码注入发生在哪里?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆