大家好,我是冰河~
字节码编程在实际的业务开发(CRUD)中并不常用,但是随着网络编程,RPC、动态字节码增强技术和自动化测试以及零侵入APM监控的不断发展与大量使用,越来越多的技术需要使用到字节码编程。
好了,我们今天就使用Javassist动态生成一个HelloWorld案例,可以直接到Github和Gitee获取。
Github:https://github.com/sunshinelyz/bytecode Gitee:https://gitee.com/binghe001/bytecode
在项目的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文件,具体如下所示。
查看IDEA的输出信息时,发现会输出如下内容。
Javassist Hello World by 冰河(公众号:冰河技术)
Process finished with exit code 0
我们使用Javassist实现了创建一个HelloWorld类的功能,字节码编程听起来貌似挺难的,但是在Javassist强大的API下,实现起来还是蛮简单的。
在接下来的一段时间里,冰河会持续输出关于字节码编程的文章,让我们一起精通字节码编程。
好了,今天就到这儿吧,我是冰河,我们下期见~~
冰河从一名普通程序员,短短几年时间,一路进阶成长为互联网高级技术专家,一直致力于分布式系统架构、微服务、分布式数据库、分布式事务与大数据技术的研究。在高并发、高可用、高可扩展性、高可维护性和大数据等领域拥有丰富的架构经验。对Hadoop,Storm,Spark,Flink等大数据框架源码进行过深度分析,并具有丰富的实战经验。
出版过三本畅销书《深入理解分布式事务:原理与实战》、《海量数据处理与大数据技术实战》、《MySQL技术大全:开发、优化与运维实战》。写了一本《深入理解高并发编程》电子书全网累计下载45W+,发布了一本全网首个开源的以实战案例为背景的《冰河的渗透实战笔记》电子书,全网五星好评。写的文章多次被微信公众号官方推荐。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有