深度探讨Java字节代码的操纵方法

Java作为业界运用最为广泛的言语之一, 更是被包括Oracle在内的众多JCP成员积极地推进开展。 毕竟是很少会有人触及的话题。 本文为IBM工程师成富编写的《Java深度历险》的第一部分Java字节代码的操纵, 希望读者们喜欢。 开发人员运用Java的方式比拟简单。 打开惯用的IDE, 编写Java源代码, 再利用IDE提供的功能直接运行Java程序就可以了。 class)。 四处运行(Writeonce, runanywhere)”的目的。 Java类文件中包含的字节代码可以被不同平台上的JVM所运用。 Java字节代码不仅可以以文件形式存在于磁盘上, JVM中的类加载器会负责从包含字节代码的字节数组(byte[])中定义出Java类。 可能会需求静态的生成Java字节代码, 或是对已有的Java字节代码进行修改。 这个时候就需求用到本文中将要引见的相关技术。 对有些运用来说, Java源代码的内容在运行时刻才能确定。 这个时候就需求静态编译源代码来生成Java字节代码, 再由JVM来加载执行。 典型的场景是很多算法竞赛的在线评测系统(如PKUJudgeOnline), 允许用户上传Java代码, 运用的做法是直接在程序中调用Java编译器。   JSR199引入了Java编译器API。 如果运用JDK6的话, 可以经过此API来静态编译Java代码。 sun. javac. Main, 不过该工具类只能编译存放在磁盘上的文件, 类似于直接运用javac命令。 这是EclipseJava开发环境运用的增量式Java编译器, 支持运行和调试有错误的代码。 该编译器也可以独自运用。 一旦发现有修改, 会自动编译Java源代码。 因此在修改代码之后, 刷新页面就可以看到变化。 运用这些静态编译的方式的时候, 比如求出来(3+4)7-10的值。 一般的做法是剖析输入的运算表达式, 思索到括号的存在和运算符的优先级等成绩, 这样的计算进程会比拟复杂, 另外一种做法是可以用JSR223引入的脚本言语支持, 直接把输入的表达式当做JavaScript或是JavaFX脚本来执行, 失掉结果。 上面的代码运用的做法是静态生成Java源代码并编译, 接着加载Java类来执行并获取结果。 这种做法完全运用Java来完成。   上面的代码给出了运用静态生成的Java字节代码的基本形式, 创建Java类的对象的实例,   Java字节代码增强  Java字节代码增强指的是在Java字节代码生成之后, 这种做法相当于对运用程序的二进制文件进行修改。 Java字节代码增强通常与Java源文件中的注解(annotation)一块运用。 注解在Java源代码中声明了需求增强的行为及相关的元数据, Java字节代码增强运用的场景比拟多, 一般都集中在增加冗余代码和对开发人员屏蔽底层的完成细节上。 用过JavaBeans的人可能对其中那些必须添加的getter/setter方法感到很繁琐, 并且难以维护。 而经过字节代码增强, getter/setter方法可以经过修改字节代码来自动添加。 用过JPA的人, 会发现实体类中被添加了一些额外的域和方法。   在讨论如何进行字节代码增强之前, 首先引见一下表示一个Java类或接口的字节代码的组织形式。 其中所包含的内容依次陈列。 如所完成的接口、域、方法和属性等, 是以数组来表示的。 有其不同的内部构造。 直接操纵包含字节代码的字节数组的话, 开发效率比拟低, 而且容易出错。 已经有不少的开源库可以对字节代码进行修改或是从头末尾创建新的Java类的字节代码内容。 运用这些类库可以在一定水平上降低增强字节代码的复杂度。 可以用一个前增强(beforeadvice)来处理这个成绩。 如果运用ASM的话, 相关的代码如下:  从ClassWriter就可以获取到包含增强之后的字节代码的字节数组, 可以把字节代码写回磁盘或是由类加载器直接运用。 上述示例中, 增强部分的逻辑比拟简单, out. 在字节代码中, Java方法体是由一系列的指令组成的。 out. println方法的指令, 并把这些指令拔出到指令集合的最后面。 ASM对这些指令做了抽象, 不过熟习全部的指令比拟困难。 ASM提供了一个工具类ASMifierClassVisitor, 当需求增强某个类的时候, 可以先在源代码上做出修改, 再经过此工具类来比拟修改前后的字节代码的差异, 从而确定该如何编写增强的代码。   对类文件进行增强的机遇是需求在Java源代码编译之后, 在JVM执行之前。 比拟常见的做法有:  在构建进程中完成, 比如经过Ant或Maven来执行相关的操作。 当获取到Java类的字节代码之后, 先进行增强处理, JDK5引入了java. lang. 基本的思路是在JVM启动的时候添加一些代理(agent)。 其清单(manifest)文件中会指定一个代理类。 这个类会包含一个premain方法。 JDK6中还允许在JVM启动之后静态添加代理。 instrument包支持两种修改的场景, 一种是重定义一个Java类, 即完全替换一个Java类的字节代码;另外一种是转换已有的Java类, 相当于后面提到的类字节代码增强。 首先需求完成java. lang. instrument.   把该代理类打成一个jar包, 并在jar包的清单文件中经过Premain-Class声明代理类的名称。 添加JVM启动参数-javaagent:myagent. jar。 这样的话, 完成相关的转换操作。 经过它, 可以很容易的对二进制分发的Java程序进行修改, 完全可以将其字节代码静态生成出来。 字节代码增强和源代码生成是不同的概念。 源代码生成之后, 对于开发人员是完全通明的。 妥善运用Java字节代码的操纵技术,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值