字节码编程|使用Javassist动态生成Hello World

简介: 字节码编程|使用Javassist动态生成Hello World

大家好,我是冰河~~

字节码编程在实际的业务开发(CRUD)中并不常用,但是随着网络编程,RPC、动态字节码增强技术和自动化测试以及零侵入APM监控的不断发展与大量使用,越来越多的技术需要使用到字节码编程。

好了,我们今天就使用Javassist动态生成一个HelloWorld案例,相关的程序案例代码

Github:https://github.com/sunshinelyz/bytecode

Gitee:https://gitee.com/binghe001/bytecode

开发环境

  • JDK 1.8
  • IDEA 2018.03
  • Maven 3.6.0

Maven依赖

在项目的pom.xml文件中添加如下环境依赖。

<properties>
    <javassist.version>3.20.0-GA</javassist.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.javassist</groupId>
        <artifactId>javassist</artifactId>
        <version>${javassist.version}</version>
    </dependency>
</dependencies>

案例效果

整体案例效果其实也是很简单的,学习Java语言时,我们会在命令行打印第一个Hello World程序。今天,我们学习Javassist字节码编程时,也来实现一个HelloWorld程序。

案例的效果就是要生成如下的程序代码。

package io.binghe.bytecode.javassist.test;
public class HelloWorld {
    public static void main(String[] var0) {
        System.out.println("Javassist Hello World by 冰河(公众号:冰河技术)");
    }
    public HelloWorld() {
    }
}

看看这个效果,像不像我们自己在IDEA中写的Java代码呢?就让我们一起使用Javassist来实现它吧。

案例实现

这个案例其实还是蛮简单的,这里就先直接给出源代码了。

/**
 * @author binghe (公众号:冰河技术)
 * @version 1.0.0
 * @description 测试使用Javassist生成第一个类HelloWorld
 */
public class GenerateHelloWorldClass {
    /**
     * 创建HelloWorld的类,并返回HelloWorld的Class实例
     */
    public static Class createHelloWorld()throws Exception{
        //使用默认的ClassPool
        ClassPool pool = ClassPool.getDefault();
        //创建一个空类
        CtClass ctClass = pool.makeClass("io.binghe.bytecode.javassist.test.HelloWorld");
        //添加一个main方法
        CtMethod ctMethod = new CtMethod(CtClass.voidType, "main", new CtClass[]{pool.get(String[].class.getName())}, ctClass);
        //将main方法声明为public static类型
        ctMethod.setModifiers(Modifier.PUBLIC + Modifier.STATIC);
        //设置方法体
        ctMethod.setBody("{" +
                "System.out.println(\"Javassist Hello World by 冰河(公众号:冰河技术)\");" +
                "}");
        ctClass.addMethod(ctMethod);
        //将生成的类的class文件输出的磁盘
        ctClass.writeFile();
        //返回HelloWorld的Class实例
        return ctClass.toClass();
    }
    public static void main(String[] args) throws Exception {
        Class clazz = createHelloWorld();
        Object obj = clazz.newInstance();
        Method mainMethod = clazz.getMethod("main", new Class[]{String[].class});
        mainMethod.invoke(obj, new String[1]);
    }
}

接下来,我们根据上述代码来看看Javassist是如何生成完整字节码的。

(1) 在createHelloWorld()方法中创建一个ClassPool,ClassPool本质上就是个CtClass对象容器。

(2) 调用ClassPool的makeClass()方法,传入完整的包名+类名生成一个空的类信息。这里传入的完整的包名+类名是io.binghe.bytecode.javassist.test.HelloWorld

(3) 给类添加方法,并设置方法的返回类型、方法名称、参数名(入参和出参)、访问修饰符以及方法体。这里设置的完整方法体如下:

public static void main(String[] var0) {
    System.out.println("Javassist Hello World by 冰河(公众号:冰河技术)");
}

(4) 尽管我们在上述代码中没有显示的创建无参构造函数,但是在编译时,Javassist会自动创建一个HelloWorld类的无参构造函数。

(5) 通过 CtClass的writeFile()方法将内存中的类信息输出到磁盘,这样我们就可以通过IDEA清晰的看到Javassist生成的HelloWorld类了。

(6) 最终在createHelloWorld()方法中调用CtClass的toClass()方法返回Class对象。

(7) 在main()方法中调用createHelloWorld()方法获取Class对象。

(8) 通过反射实例化对象,并通过反射调用生成的HelloWorld类的main()方法。

效果演示

运行GenerateHelloWorldClass类的main()方法,会在顶级工程目录下的io/binghe/bytecode/javassist/test 目录下生成HelloWorld.class文件,具体如下所示。

image.png

查看IDEA的输出信息时,发现会输出如下内容。

Javassist Hello World by 冰河(公众号:冰河技术)
Process finished with exit code 0

案例总结

我们使用Javassist实现了创建一个HelloWorld类的功能,字节码编程听起来貌似挺难的,但是在Javassist强大的API下,实现起来还是蛮简单的。

在接下来的一段时间里,冰河会持续输出关于字节码编程的文章,让我们一起精通字节码编程。

好了,今天就到这儿吧,我是冰河,我们下期见~~

相关文章
|
4月前
|
Java 编译器
Java编译器注解运行和自动生成代码问题之如何定义@BuildProperty注解
Java编译器注解运行和自动生成代码问题之如何定义@BuildProperty注解
|
5月前
|
Java 对象存储
字节码学习之常见java语句的底层原理
字节码学习之常见java语句的底层原理
39 0
|
6月前
|
安全 Java 开发工具
第一个java程序helloworld代码的编写
第一个java程序helloworld代码的编写
106 0
|
IDE 数据可视化 Java
查看Java字节码内容的几种方式
查看Java字节码内容的几种方式
Java工具篇之Javassist字节码编程
Javassist是一个开源的分析、编辑和创建Java字节码的类库,可以直接编辑和生成Java生成的字节码。 相对于bcel, asm等这些工具,开发者不需要了解虚拟机指令,就能动态改变类的结构,或者动态生成类。javassist简单易用, 快速。
417 0
|
Java 缓存 测试技术
Groovy&Java动态编译执行
Groovy&Java动态编译执行 工作中,遇到部分业务经常动态变化,或者在不发布系统的前提下,对业务规则进行调整。那么可以将这部分业务逻辑改写成Groovy脚本来执行,那么就可以在业务运行过程中动态更改业务规则,达到快速响应。
2010 0
|
存储 缓存 前端开发
【JVM源码解析】模板解释器解释执行Java字节码指令(上)
【JVM源码解析】模板解释器解释执行Java字节码指令(上)
【JVM源码解析】模板解释器解释执行Java字节码指令(上)
|
存储 缓存 前端开发
【JVM源码解析】模板解释器解释执行Java字节码指令(下)
【JVM源码解析】模板解释器解释执行Java字节码指令(下)
【JVM源码解析】模板解释器解释执行Java字节码指令(下)
|
Java
【Groovy】Groovy 代码创建 ( 使用 Java 语法实现 Groovy 类和主函数并运行 | 按照 Groovy 语法改造上述 Java 语法规则代码 )
【Groovy】Groovy 代码创建 ( 使用 Java 语法实现 Groovy 类和主函数并运行 | 按照 Groovy 语法改造上述 Java 语法规则代码 )
246 0
【Groovy】Groovy 代码创建 ( 使用 Java 语法实现 Groovy 类和主函数并运行 | 按照 Groovy 语法改造上述 Java 语法规则代码 )
|
监控 Java 测试技术
字节码编程,Javassist篇一《基于javassist的第一个案例helloworld》
在字节码编程方面有三个比较常见的框架;ASM、byte-buddy、Javassist,他们都可以对这字节码进行操作,只是操作方式和控制粒度不同。 其中 「ASM」 更偏向于底层,需要了解 「JVM」 虚拟机中指定规范以及对局部变量以及操作数栈的知识。虽然在编写起来比较麻烦,但是它也是性能最好功能最强的字节码操作框架。常见的会用在 「CGLIB」 动态代理类中,以及一些非入侵的探针监控场景中。 另外两个框架都是有强大的 API,操作使用上更加容易控制。虽然对对比上会比 「ASM」 性能差一些,但不是说性能完全不好。同样在一些监控场景中也用的非常多。如果你细心可以在你的工程 「jar」 包搜索一
323 0
字节码编程,Javassist篇一《基于javassist的第一个案例helloworld》
下一篇
无影云桌面