[Java] 动态生成类的场景的考察

开个坑慢慢填哈。

============================================

Oracle/Sun JDK / OpenJDK的Java SE中的场景


在Oracle/Sun JDK及OpenJDK内,动态生成类(字节码)的场景有:


其中MethodHandle的LambdaForm实现与Nashorn都是比较新的实现,它们里面有些思路是相当有趣的。回头再展开来说。例如它们会为了有效地存储数据而根据需要的数据类型/结构来生成存储数据的对象。例如说Nashorn里实现可以存8个字段的JavaScript对象的背后的Java类,是一个叫做“JO8”的类,而这个类就是根据需要动态生成出来的。同理,MethodHandle中有一系列叫做“BoundMethodHandle”的东西,可以捕获参数的值(读作“currying”),其存储参数的类也是动态生成出来的,例如说Species_LII表示能按顺序保存1个引用类型、2个int类型字段的类。

Java 7新加入的invokedynamic指令现在被广泛应用于“compact encoding of boilerplate code”(我得想想怎么组织语言来用中文说…)。上面提到的Java lambda表达式、indify string concat都是这样的例子。

============================================

其它场景



在需要动态访问Java对象属性但又需要规避反射开销的地方,动态字节码生成也是很常见的。例如:

  • (待补充)


在JVM上实现的动态语言,要性能好的话,生成Java字节码也是必经之路。有些语言可以静态编译出Java Class(例如Groovy),而更多还是在运行时生成Class(有些可能可以缓存生成的Class)。除了前面提到的Nashorn外,动态生成字节码的还例如:

  • JRuby
  • Jython
  • (待补充)


比完整的编程语言更轻量级的“表达式语言”(expression language)也很流行用动态字节码生成。例如:

  • MVEL
  • (待补充)


有些本来是可以静态编译的、在JVM上实现的语言,为了减小发布的JAR包大小,也有可能会选择用动态类生成来仅在运行时需要某些类的时候才将它们生成出来。例如:

  • Scala
  • Fortress
  • (待补充)


有些模版引擎为了提升渲染速度,也会选择做字节码生成。例如:

  • 各种JSP实现。例如Tomcat会把JSP先生成为Java源码,然后用Eclipse JDT(或者叫ECJ)将其编译到Java字节码。
  • 淘宝以前尝试过将原本是在AST上解释执行来实现渲染的Velocity模版引擎,改造为将Velocity模版编译为等价的Java源码然后再编译到Java字节码的编译版。



在动态做bytecode instrumentation的地方(或者说Java类的redefine / retransform)的地方,显然也会用到动态字节码生成。例如说:

  • BTrace
  • 某些AOP实现
  • (待补充)


有些测试框架会做mock,这些mock类也常常是通过proxy来实现的,所以也会用到上述场景中的其中一些(例如JDK自带的Proxy类)。


============================================


说到动态字节码生成,顺带考察一下一些常用的工具 / 库吧。



============================================


还有啥有趣的大类别这里遗漏了的,或者是每个大类别下有哪些您觉得有趣的例子的,欢迎在评论中补充 ^_^ 我也会慢慢补充上我知道的一些,并且对某些点稍微展开来说说动态生成了怎样的类。

14 条评论