二十四 运行时动态生成一个类

  1. 一些思路
    我们可以从常见的 Java 类来源分析,通常的开发过程是,开发者编写 Java 代码,调用 javac 编译成 class 文件,然后通过类加载机制载入 JVM,就成为应用运行时可以使用的 Java 类了。
  • 一个直接的方式是从源码入手,可以利用 Java 程序生成一段源码,然后保存到文件等. 使用 Java Compiler API(这是 JDK 提供的标准 API,里面提供了与 javac 对等的编译器功能) 进行编译, 最后再用类加载器,在运行时加载即可。
  • 另个思路, 只要是符合JVM规范的字节码,不管他是如何生成的, 都可以被JVM加载, 不过直接去写字节码难度太大,通常我们可以利用 Java 字节码操纵工具和类库来实现,比如在ASM(java自带,动代之类就用这个), Javassist、cglib 等
  1. 类从字节码到 Class 对象的转换
    在类加载过程中,这一步是通过下面的方法(还有几个重载, 在ClassLoader类中)提供的功能
 protected final Class defineClass(String name, byte[] b, int off, int len,
                                         ProtectionDomain protectionDomain)

更进一步,我们来看看 JDK dynamic proxy 的实现代码。你会发现,对应逻辑是实现在 ProxyBuilder 这个静态内部类中,ProxyGenerator 生成字节码,并以 byte 数组的形式保存,然后通过调用 Unsafe 提供的 defineClass 入口。

byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
        proxyName, interfaces.toArray(EMPTY_CLASS_ARRAY), accessFlags);
try {
    Class pc = UNSAFE.defineClass(proxyName, proxyClassFile,
                                    0, proxyClassFile.length,
                                   loader, null);
    reverseProxyCache.sub(pc).putIfAbsent(loader, Boolean.TRUE);
    return pc;
} catch (ClassFormatError e) {
      // 如果出现 ClassFormatError,很可能是输入参数有问题,比如,ProxyGenerator 有 bug
}

//结合第六篇 动态代理

  1. 字节码操纵技术
    (动态代理就使用了)

你可能感兴趣的:(二十四 运行时动态生成一个类)