大家好,我是冰河~~字节码编程在实际业务开发中并不常用(CRUD),但是随着网络编程、RPC、动态字节码增强技术和自动化的不断发展和广泛使用测试和零侵入式APM监控,越来越多的技术需要使用字节码编程。好了,今天我们就用Javassist动态生成一个HelloWorld案例。相关程序案例代码可通过关注公众号:冰川科技,或直接从Github和Gitee获取。Github:https://github.com/sunshinelyz/bytecodeGitee:https://gitee.com/binghe001/bytecode开发环境JDK1.8IDEA2018.03Maven3.6.0Maven依赖在pom.xml文件中添加如下环境依赖该项目。3.20.0-GAorg.javassistjavassist<版本>${javassist.version}案例效果整体案例效果其实很简单。在学习Java语言时,我们会在命令行打印第一个HelloWorld程序。今天我们在学习Javassist字节码编程的时候,也实现了一个HelloWorld程序。案例效果是生成如下程序代码。packageio.binghe.bytecode.javassist.test;publicclassHelloWorld{publicstaticvoidmain(String[]var0){System.out.println("JavasistHelloWorldbyGlacier(公众号:GlacierTechnology)");}publicHelloWorld(){}}看看这个效果是不是像我们写的Java代码在想法?让我们使用Javassist来实现它。案例实现这个案例其实很简单,所以这里是源代码。/***@authorbinghe(公众号:冰川科技)*@version1.0.0*@description测试使用Javassist生成第一个类HelloWorld*/publicclassGenerateHelloWorldClass{/***创建一个HelloWorld类并返回HelloWorld的Class实例*/publicstaticClasscreateHelloWorld()throwsException{//使用默认的ClassPoolClassPoolpool=ClassPool.getDefault();//创建一个空类CtClassctClass=pool.makeClass("io.binghe.bytecode.javassist.test.HelloWorld");//添加AmainmethodCtMethodctMethod=newCtMethod(CtClass.voidType,"main",newCtClass[]{pool.get(String[].class.getName())},ctClass);//声明main方法为公共静态类型ctMethod。setModifiers(Modifier.PUBLIC+Modifier.STATIC);//设置方法体ctMethod.setBody("{"+"System.out.println(\"JavasistHelloWorldbyGlacier(公众号:冰川科技)\");"+"}");ctClass.addMethod(ctMethod);//将生成的类的class文件输出到磁盘ctClass.writeFile();//返回HelloWorld的Class实例returnctClass.toClass();}publicstaticvoidmain(String[]args)throwsException{Classclazz=createHelloWorld();Objectobj=clazz.newInstance();MethodmainMethod=clazz.getMethod("main",newClass[]{String[].class});mainMethod.invoke(obj,newString[1]);}}接下来我们看看Javassist是如何根据上面的代码生成完整的字节码的(一)创建createHelloWorld()方法中的一个ClassPool,本质上是一个CtClass对象容器。(2)调用ClassPool的makeClass()方法,传入完整的包名+类名,生成一个空的类信息。这里传递的完整包名+类名是io.binghe.bytecode.javassist.test.HelloWorld。(3)在类中添加一个方法,并设置方法的返回类型、方法名、参数名(入参和出参)、访问修饰符和方法体。这里设置的完整方法体如下:publicstaticvoidmain(String[]var0){System.out.println("JavasistHelloWorldbyGlacier(公众号:GlacierTechnology)");}(4)虽然我们没有展示创建无参构造函数,但在编译时,Javassist会自动为HelloWorld类创建一个无参构造函数。(5)通过CtClass的writeFile()方法将内存中的类信息输出到磁盘中,这样我们就可以清楚的看到Javassist通过IDEA生成的HelloWorld类。(6)最后在createHelloWorld()方法中调用CtClass的toClass()方法返回Class对象。(7)在main()方法中,调用createHelloWorld()方法获取Class对象。(8)通过反射实例化对象,通过反射调用生成的HelloWorld类的main()方法。效果演示运行GenerateHelloWorldClass类的main()方法,会在项目顶层目录下的io/binghe/bytecode/javassist/test目录下生成HelloWorld.class文件,如下图。在查看IDEA的输出信息时,发现会输出如下内容。JavassistHelloWorldbyGlacier(公众号:冰川科技)Processfinishedwithxitcode0案例总结我们使用Javassist实现了创建HelloWorld类的功能。字节码编程听起来很难,但是在Javassist强大的API下,实现起来还是相当简单的。在接下来的一段时间里,冰河会继续输出关于字节码编程的文章,让我们一起掌握字节码编程。好了,今天就这些了,我是冰河,我们下期再见~~本文转载自微信公众号“冰河科技”,可以通过以下二维码关注。转载本文请联系冰川科技公众号。