`

【Java核心-进阶】运行时动态生成Java类

    博客分类:
  • Java
 
阅读更多

技术上可行的方式

生成源码文件 -> 编译源码 -> 加载类

方式1:javac 编译

可以用 ProcessBuilder 这个类启动 javac 进程,编译源码文件

 

方式2:Java Compiler API 编译

JDK中的 Java Compiler API 提供了与 javac 对等的编译能力。(示例:InMemoryJavaCompiler

 

直接生成字节码 -> 加载类

一般通过字节码操作工具和类库来更改Java Class的字节码。
流行的工具有 ASMJavassistcglibByte Buddy 等。
很多工具/框架中的动态代理实现中就有用到这些工具。如,Spring框架内置了 cglib

 

字节码 -> Class

将字节码转换为 Class 发生在类加载过程中(《Java类加载》)。
可通过 ClassLoader.defineClass 方法将字节码转换成Class对象。
或者使用JDK中其它对等的方法(不同版本的JDK会略有不同)。

public abstract class ClassLoader {
  protected final Class<?> defineClass(
      String name, byte[] b, int off, int len,
      ProtectionDomain protectionDomain);

  protected final Class<?> defineClass(
      String name, java.nio.ByteBuffer b,
      ProtectionDomain protectionDomain);

  static native Class<?> defineClass1(
      ClassLoader loader, String name, byte[] b, int off, int len,
      ProtectionDomain pd, String source);

  static native Class<?> defineClass2(
      ClassLoader loader, String name, java.nio.ByteBuffer b,
      int off, int len, ProtectionDomain pd, String source);
  ...
}

 

操作字节码

JDK 动态代理实现方式

JDK动态代理实现的方式是比较hack的,需要了解JVM指令,偏移地址的处理也比较繁琐。
ProxyGenerator 类源码可以看出这种方式的使用门槛非常高,不适合普通开发场景。

 

更抽象方便的类库(ASM等)

JDK内部集成了ASM类库。如,命名空间 jdk.internal.org.objectweb.asm 下的 ClassWriter 类提供了一组用于生成字节码的方法。

public class ClassWriter extends ClassVisitor {
  // 构建 Class 签名(指定Java版本、访问权限、名称、父类、实现接口等)
  public final void visit(
      final int version, final int access, final String name,
      final String signature, final String superName,
      final String[] interfaces);

  // 构建方法
  public final MethodVisitor visitMethod(
      final int access, final String name, final String descriptor,
      final String signature, final String[] exceptions);

  // 结束字节码生成
  public final void visitEnd();

  // 输出字节码,用于前述的 ClassLoader 载入该新建的类
  public byte[] toByteArray();
  ...
}

public abstract class MethodVisitor {
  // 构建方法内部代码
  public void visitCode();
  ...
}

 

ASM中的 Visitor 模式

在生成/修改字节码的大多数场景中,都是依赖特定结构,修改或新增 方法、变量、类型等。
而Visitor模式的优势就是将算法和对象结构解耦,所以ASM API广泛使用了该模式。

 

字节码操作技术的使用场景

大多数业务不会直接使用字节码操作技术,但它是很多工具和底层框架必不可少的部分。
Mock 框架、ORM 框架、IOC 容器、Profiler或运行时诊断工具、形式化代码生成工具 等都会用到字节码操作技术。
 

在一些资源消耗统计的场景中也经常出现字节码操作技术的身影。
如,为了统计某些方法调用的网络通信的消耗,我们可以通过 JavaAgent + 字节码操作技术 来改变相关类,植入统计相关数据的代码。
这种方式不会侵入原业务代码,比AOP的方式更干净。而且不开启统计功能时,是零开销

 

分享到:
评论

相关推荐

    Java语言程序设计-进阶篇(原书第8版)

    根据提供的标题“Java语言程序设计-进阶篇(原书第8版)”,我们可以推测这本书主要聚焦于Java编程语言的高级应用与实践。虽然描述部分为空白,但是结合标题和标签,可以推断出该书内容涉及Java语言的深层次理解和实际...

    2011.06 - Java语言程序设计-进阶篇(原书第8版

    在Java进阶篇中,会详细介绍List、Set、Map等集合类型的使用场景、性能特点及其提供的各种操作方法。 3. 泛型编程:泛型是Java SE 5版本中引入的一个重要特性,它允许在编译时提供类型安全检查,同时避免了类型转换...

    Java语言程序设计-进阶篇(原书第8版)

    标签“Java 进阶篇 第8版”进一步印证了这本书的定位,即作为Java学习者的进阶指南,并且已经更新到最新版,这可能意味着书中内容与Java的最新版本——截至本知识生成时,Java 16——同步,包含了最新的API和语言...

    Java语言程序设计-进阶篇(原书第8版).

    由于提供的【部分内容】重复且无效,无法从中提取有效知识点,所以我将基于标题和描述来生成关于Java语言程序设计进阶篇的相关知识点。 Java是一种高级的面向对象编程语言,它以其平台无关性、安全性、稳定性和性能...

    [Java语言程序设计-进阶篇(原书第8版)](高清)

    - **反射**:Class类、Field类、Method类等的使用,实现运行时动态获取类的信息并进行操作的能力。 #### 6. Lambda表达式与Stream API - **Lambda表达式**:简化函数式接口的实现方式,提高代码的可读性和简洁性。...

    gtk学习代码-进阶版

    GTK,全称GIMP Toolkit,是一个用于创建图形用户界面(GUI)的开源工具包,广泛应用于Linux和其他类Unix系统。这个“gtk学习代码-进阶版”压缩包很可能是为那些已经对GTK基础有一定了解,想要深入研究和提升GTK编程...

    Java基础,Java进阶,Java数据结构,十大算法

    接下来是“Java进阶”部分,这部分将深入探讨更多高级特性: 1. **多线程**:Java提供的Thread类和Runnable接口,线程同步机制(synchronized关键字、wait/notify、Lock锁)以及并发工具类。 2. **网络编程**:套...

    Java JNI 编程进阶

    - 使用JNI的开发流程通常包括编写Java代码、生成JNI头文件、编写本地代码实现、编译本地代码并生成库文件、最后在Java中加载库文件并调用本地方法。 总之,Java JNI编程进阶涉及到性能优化、本地系统接口调用和...

    2020老杜最新Java零基础进阶视频教程-常用类课件

    - 反射允许在运行时检查类的信息(如方法、字段、构造器),动态创建对象和调用方法。 【关于String】 - `String`是不可变对象,意味着一旦创建,其内容不能改变。如在代码中`s1=s1 + s2;`会创建一个新的`String`...

    5-java进阶-枚举与注解1

    * 枚举是一种特殊的类,它继承自 java.lang.Enum 类。 * 枚举中的常量是public、static、final 的。 * 枚举可以使用toString()方法来获取枚举的名称。 * 枚举可以使用values()方法来获取枚举的所有常量。 * 枚举可以...

    Java 7编程高级进阶

    `java.util.concurrent.ForkJoinPool`和`java.util.concurrent.RecursiveTask`是其核心类。 7. **非阻塞堆栈跟踪(Non-blocking Stack Traces)** 当线程处于等待状态时,Java 7可以生成不包含阻塞信息的堆栈跟踪...

    java大神进阶之路.pdf

    Java大神进阶之路是一份针对Java开发者进阶提升的学习指南,详细描述了从编程基础到Java语言本身的精通,再到数据库以及Java Web核心技术的掌握,以及每个阶段所需要学习和掌握的知识点。文中特别强调了数据结构和...

    Java进阶基础.zip

    "Java进阶基础.zip"这个压缩包很可能包含了帮助开发者深化Java理解的材料,涵盖了从核心概念到高级特性的各个方面。以下是一些可能涵盖的Java进阶基础知识: 1. **异常处理**:Java的异常处理机制是其强项之一,...

    Java语言程序设计 进阶篇 源代码与答案

    7. **反射**:反射机制允许在运行时检查类的信息并动态调用方法。在某些场景下,如插件系统或框架开发,反射的应用非常关键。 8. **注解(Annotation)**:注解提供了元数据,可以用于代码的编译、运行时验证和工具...

    JAVA项目---个人博客

    总的来说,这个"JAVA项目---个人博客"是一个综合性的学习资源,涵盖了Web开发的基础和进阶知识,包括服务器端编程(JSP和Servlet)、前端交互(JavaScript)、页面组件复用(iframe)以及安全性措施(验证码)。...

    Java Web整合开发进阶100例.pdf

    3. **Servlet与JSP技术**:Servlet是运行在服务器端的小型Java程序,负责接收客户端请求,执行业务逻辑,生成动态内容并返回响应。JSP则是将Java代码嵌入到HTML页面中的技术,它允许开发者将动态内容直接嵌入到页面...

    推荐优质Java课程 疯狂Java语言编程 Java入门到进阶教程 01.Java语言概述(共21页).ppt

    学习Java时,首先需要安装Java Development Kit(JDK),它包含了编译和运行Java程序所需的工具,如`javac.exe`(编译器)和`java.exe`(解释器)。安装JDK后,还需要设置环境变量PATH,以便在命令行中可以全局访问...

    JAVA核心技术--高级特征(第八版)--第四部分

    3. **反射**:反射允许程序在运行时检查和操作类、接口、字段和方法,这是Java动态性的一个重要体现。学习反射可以理解如何在运行时创建对象、调用方法和访问私有成员。 4. **注解(Annotation)**:注解是一种元...

    编程实践:Java Web整合开发进阶100例[清晰完整版]

    2. **JSP**:Java Server Pages是用于动态生成HTML的工具,它将Java代码嵌入到HTML中,使得网页具有更强的动态性。书中将涵盖JSP指令、脚本元素、EL(表达式语言)和JSTL(JavaServer Pages Standard Tag Library)...

Global site tag (gtag.js) - Google Analytics