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

Java做为业界使用最为广泛的语言之一, 深得众多软件厂商和开发者的推崇, 可是关于Java语言的深度了解和运用, 本文为IBM工程师成富编写的《Java深度历险》的第一部分Java字节代码的操纵, 编写Java源代码, 再利用IDE提供的功能直接运转Java顺序就能够了。 java), IDE会担任调用Java的编译器把Java源代码编译成平台无关的字节代码(bytecode), 以类文件的形式保存在磁盘上(. class)。 Java虚拟机(JVM)会担任把Java字节代码加载并执行。 Java通过这种方式来实现其“编写一次, 四处运转(Writeonce, runanywhere)”的目的。 JVM中的类加载器会担任从包括字节代码的字节数组(byte[])中定义出Java类。 可能会须要动态的生成Java字节代码, 或是对已有的Java字节代码中止修改。 这个时候就须要用到本文中将要介绍的相关技术。   动态编译Java源文件  在普通状况下, 开发人员都是在顺序运转以前就编写完成了所有的Java源代码而且成功编译。 对有些使用来讲, Java源代码的内容在运转时辰才干肯定。 再由JVM来加载执行。 由系统在后台编译、运转并中止判定。 使用的作法是直接在顺序中调用Java编译器。 可使用JDK中的工具类com. sun. Main, 不过该工具类只能编译寄存在磁盘上的文件,   另一个可用的工具是EclipseJDTCore提供的编译器。 这是EclipseJava开发环境使用的增量式Java编译器, Play框架在内部使用了JDT的编译器来动态编译Java源代码。 在开发模式下, 于是在修改代码以后, 刷新页面就能够看到变化。 须要确保JDK中的tools. jar在使用的CLASSPATH中。 是关于如何在Java外面作四则运算, 好比求出来(3+4)7-10的值。 普通的作法是剖析输出的运算表达式, 考虑到括号的存在和运算符的优先级等成果, 另一种作法是能够用JSR223引入的脚本语言支持, 直接把输出的表达式当作JavaScript或是JavaFX脚本来执行, 上面的代码使用的作法是动态生成Java源代码并编译, 接着加载Java类来执行并获取结果。 这种作法彻底使用Java来实现。   上面的代码给出了使用动态生成的Java字节代码的基本模式, 即通过类加载器来加载字节代码, 创立Java类的对象的实例,   Java字节代码增强  Java字节代码增强指的是在Java字节代码生成以后, 这种作法至关于对使用顺序的二进制文件中止修改。 注解在Java源代码中声明了须要增强的行为及相关的元数据, 用过JavaBeans的人可能对其中那些必需添加的getter/setter方法感到很繁琐, 而通过字节代码增强, 开发人员只须要声明Bean中的属性便可, getter/setter方法能够通过修改字节代码来自动添加。 用过JPA的人, 在调试顺序的时候, 会发现实体类中被添加了一些额外的域和方法。 首先介绍一下表示一个Java类或接口的字节代码的组织形式。   类文件  如上所示, 一个类或接口的字节代码使用的是一种松懈的组织构造, 关于可能包括多个条目的内容, 如所实现的接口、域、方法和属性等, 是以数组来表示的。 不一样的内容类型, 关于开发人员来讲, 直接操纵包括字节代码的字节数组的话, 开发效率比拟低, 这些类库包括ASM、cglib、serp和BCEL等。 好比考虑上面一个复杂的需求, 在一个Java类的全部方法执行以前输出相应的日志。 熟悉AOP的人都晓得, 相关的代码以下:  从ClassWriter就能够获取到包括增强以后的字节代码的字节数组, 增强部分的逻辑比拟复杂, 只是遍历Java类中的全部方法并添加对System. println方法的调用。 在字节代码中, 而要作的是生成调用System. 并把这些指令插入到指令集合的最前面。 ASM对这些指令作了抽象, ASM提供了一个工具类ASMifierClassVisitor, 当须要增强某个类的时候, 能够先在源代码上作出修改, 在JVM执行以前。 当获取到Java类的字节代码以后, 先中止增强处理,   因为存在着少许对Java字节代码中止修改的需求, lang. instrument包并在JDK6中失掉了进一步的增强。 这个类会包括一个premain方法。 JVM在启动的时候会首先执行代理类的premain方法, 再执行Java顺序自己的main方法。 在premain方法中就能够对顺序自己的字节代码中止修改。 JDK6中还容许在JVM启动以后动态添加代理。 java. instrument包支持两种修改的场景, 一种是重定义一个Java类, 即彻底交流一个Java类的字节代码;另一种是转换已有的Java类, 至关于前面提到的类字节代码增强。 首先须要实现java. lang. instrument. ClassFileTransformer接口来完成对已有Java类的转换。   把该代理类打成一个jar包, 运转Java顺序的时候, 添加JVM启动参数-javaagent:myagent. jar。 这样的话, 完成相关的转换操做。 能够很容易的对二进制分发的Java顺序中止修改, 十分适宜于性能剖析、调试跟踪和日志记载等义务。 另一个十分重要的做用是把开发人员从繁琐的Java语法中解放出来。 开发人员应该只须要担任编写与业务逻辑相关的重要代码。 关于那些只是因为语法要求而添加的, 或是模式固定的代码, 彻底能够将其字节代码动态生成出来。 字节代码增强和源代码生成是不一样的概念。 源代码生成以后, 就已经成为了顺序的一部分, 开发人员须要去维护它:要么手工修改生成出来的源代码, 要么重重生成。 关于开发人员是彻底透明的。 妥善使用Java字节代码的操纵技术, 能够更好的解决某一类开发成果。java

相关文章
相关标签/搜索