哪里字节code注射液发生呢? [英] Where does bytecode injection happen?

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

问题描述

动机

我有一个 SomeObject.java 文件:

 类SomeObject {
   字符串名称;
}

编译它创建一个字节$ C $ SomeObject.class 文件,其中包含C-

  0xCAFEBABE ...

如果我们在JVM上使用SomeObject,它是由当前的类加载器加载和一切工作正常。

现在让我们假设,我想有一些动态的code一代。我可以写我的自定义注释

  @Target(ElementType.TYPE)
公共@interface数据{
   ...
}

和其添加为改性剂类声明:

  @Data
类SomeObject {
   字符串名称;
}

我也可以保留它的运行时间 @Retention(RetentionPolicy.RUNTIME)

  @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
公共@interface数据{
   ...
}

问题

当用于字节code注射液注解?是否有相应的运行时加载的类时,一个类加载器注入字节code在本图保留注释,如:

 源 - (编译) -  GT;字节code  - (类加载器字节code注射液) -  GT;注射字节code  - (类加载) -  GT; JVM加载字节code


解决方案

是的,这将有可能有您的自定义类加载器加载类,并通过字节code操作工具,如的Javassist ASM 执行修改,加载到内存中没有字节code中的类文件,而是修改之一。
虽然有比较容易(和更好的,在我看来)做这件事的方法。

注解处理器工具(APT)

由于Java 6,你有 APT ,让你上钩进入编译过程(通过 -processor ​​参数中的javac)。随着APT您有机会获得code的AST(抽象语法树),你可以使用<一个编译时直接进行修改, href=\"http://docs.oracle.com/javase/7/docs/api/javax/lang/model/package-summary.html\">javax.lang.model.这意味着你的类文件将与必要的修改产生。

在这种情况下,链会像这样的:

源 - (编译和模型级进行修改) - GT;字节code已经修改 - 普通类加载器 - &GT;类加载到内存

后编译处理

可以使用的另一种方法是汇编作为后编译过程之后执行字节code注射液。在此情况下,使用字节code修改工具(再次Javassist进行,ASM,等等),它可以执行需要时所需的注释被发现的修改,产生一个新的类文件与注入的字节code

在这种情况下,你的链条是:

源-compile - &GT;字节code -post-之前编制&GT;修改字节code - 普通类加载器 - &GT;类加载到内存

运行时修改

最后,我们达成的运行时字节code修改。即使你的想法是可行的,在我看来,我会离开的类加载器的魔术的和使用的工具,拥有了Javassist也可以让你有<一个href=\"http://www.csg.is.titech.ac.jp/~chiba/javassist/html/javassist/util/proxy/package-summary.html\">dynamic代理可以进行修改和<一href=\"http://www.csg.is.titech.ac.jp/~chiba/javassist/html/javassist/util/HotSwapper.html\">reloaded.

在了Javassist特定情况下的链条会

源-compile - &GT;字节code -post-之前编制&GT;修改字节code - 普通类加载器 - &GT;加载到内存中 - Javassist进行代理 - &GT;修改的类 - 热Javassist进行交换技术 - &GT;重新修改的类

代理是不完美的,但(也没有什么)。你将有一个性能命中,你将不能修改类的公共接口(旁注:APT和后期编译过程可以让你修改类的公共接口)。我还可以多一点这一点,但我认为这已经是足够的信息,让您回味无穷。随意如果你需要更多的信息来发表评论。

Motivation

I have a SomeObject.java file:

class SomeObject {
   String name;
}

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

0xCAFEBABE...

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;
}

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   

解决方案

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.

Annotation Processor Tool (APT)

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 -(compile and performs modifications at model level)-> bytecode already modified - regular class loader -> loads class into memory

Post-Compiling processing

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 -> bytecode -post-compile-> modified bytecode - regular class loader -> loads class into memory

Runtime modifications

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.

In javassist particular case the chain would be

source -compile -> bytecode -post-compile-> modified bytecode - regular class loader -> loaded into memory - javassist proxy -> modified class - javassist hot swapper -> re-modified class

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.

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

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