使用 Javassist 動(dòng)態(tài)生成 Hello World
大家好,我是冰河~~
字節(jié)碼編程在實(shí)際的業(yè)務(wù)開發(fā)(CRUD)中并不常用,但是隨著網(wǎng)絡(luò)編程,RPC、動(dòng)態(tài)字節(jié)碼增強(qiáng)技術(shù)和自動(dòng)化測(cè)試以及零侵入APM監(jiān)控的不斷發(fā)展與大量使用,越來(lái)越多的技術(shù)需要使用到字節(jié)碼編程。
好了,我們今天就使用Javassist動(dòng)態(tài)生成一個(gè)HelloWorld案例,相關(guān)的程序案例代碼可以關(guān)注公眾號(hào):冰河技術(shù) 獲取,也可以直接到Github和Gitee獲取。
Github:https://github.com/sunshinelyz/bytecode
Gitee:https://gitee.com/binghe001/bytecode
開發(fā)環(huán)境
- JDK 1.8
- IDEA 2018.03
- Maven 3.6.0
Maven依賴
在項(xiàng)目的pom.xml文件中添加如下環(huán)境依賴。
- <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>
案例效果
整體案例效果其實(shí)也是很簡(jiǎn)單的,學(xué)習(xí)Java語(yǔ)言時(shí),我們會(huì)在命令行打印第一個(gè)Hello World程序。今天,我們學(xué)習(xí)Javassist字節(jié)碼編程時(shí),也來(lái)實(shí)現(xiàn)一個(gè)HelloWorld程序。
案例的效果就是要生成如下的程序代碼。
- package io.binghe.bytecode.javassist.test;
- public class HelloWorld {
- public static void main(String[] var0) {
- System.out.println("Javassist Hello World by 冰河(公眾號(hào):冰河技術(shù))");
- }
- public HelloWorld() {
- }
- }
看看這個(gè)效果,像不像我們自己在IDEA中寫的Java代碼呢?就讓我們一起使用Javassist來(lái)實(shí)現(xiàn)它吧。
案例實(shí)現(xiàn)
這個(gè)案例其實(shí)還是蠻簡(jiǎn)單的,這里就先直接給出源代碼了。
- /**
- * @author binghe (公眾號(hào):冰河技術(shù))
- * @version 1.0.0
- * @description 測(cè)試使用Javassist生成第一個(gè)類HelloWorld
- */
- public class GenerateHelloWorldClass {
- /**
- * 創(chuàng)建HelloWorld的類,并返回HelloWorld的Class實(shí)例
- */
- public static Class createHelloWorld()throws Exception{
- //使用默認(rèn)的ClassPool
- ClassPool pool = ClassPool.getDefault();
- //創(chuàng)建一個(gè)空類
- CtClass ctClass = pool.makeClass("io.binghe.bytecode.javassist.test.HelloWorld");
- //添加一個(gè)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);
- //設(shè)置方法體
- ctMethod.setBody("{" +
- "System.out.println(\"Javassist Hello World by 冰河(公眾號(hào):冰河技術(shù))\");" +
- "}");
- ctClass.addMethod(ctMethod);
- //將生成的類的class文件輸出的磁盤
- ctClass.writeFile();
- //返回HelloWorld的Class實(shí)例
- 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]);
- }
- }
接下來(lái),我們根據(jù)上述代碼來(lái)看看Javassist是如何生成完整字節(jié)碼的。
(1) 在createHelloWorld()方法中創(chuàng)建一個(gè)ClassPool,ClassPool本質(zhì)上就是個(gè)CtClass對(duì)象容器。
(2) 調(diào)用ClassPool的makeClass()方法,傳入完整的包名+類名生成一個(gè)空的類信息。這里傳入的完整的包名+類名是io.binghe.bytecode.javassist.test.HelloWorld。
(3) 給類添加方法,并設(shè)置方法的返回類型、方法名稱、參數(shù)名(入?yún)⒑统鰠?、訪問(wèn)修飾符以及方法體。這里設(shè)置的完整方法體如下:
- public static void main(String[] var0) {
- System.out.println("Javassist Hello World by 冰河(公眾號(hào):冰河技術(shù))");
- }
(4) 盡管我們?cè)谏鲜龃a中沒有顯示的創(chuàng)建無(wú)參構(gòu)造函數(shù),但是在編譯時(shí),Javassist會(huì)自動(dòng)創(chuàng)建一個(gè)HelloWorld類的無(wú)參構(gòu)造函數(shù)。
(5) 通過(guò) CtClass的writeFile()方法將內(nèi)存中的類信息輸出到磁盤,這樣我們就可以通過(guò)IDEA清晰的看到Javassist生成的HelloWorld類了。
(6) 最終在createHelloWorld()方法中調(diào)用CtClass的toClass()方法返回Class對(duì)象。
(7) 在main()方法中調(diào)用createHelloWorld()方法獲取Class對(duì)象。
(8) 通過(guò)反射實(shí)例化對(duì)象,并通過(guò)反射調(diào)用生成的HelloWorld類的main()方法。
效果演示
運(yùn)行GenerateHelloWorldClass類的main()方法,會(huì)在頂級(jí)工程目錄下的io/binghe/bytecode/javassist/test 目錄下生成HelloWorld.class文件,具體如下所示。
查看IDEA的輸出信息時(shí),發(fā)現(xiàn)會(huì)輸出如下內(nèi)容。
- Javassist Hello World by 冰河(公眾號(hào):冰河技術(shù))
- Process finished with exit code 0
案例總結(jié)
我們使用Javassist實(shí)現(xiàn)了創(chuàng)建一個(gè)HelloWorld類的功能,字節(jié)碼編程聽起來(lái)貌似挺難的,但是在Javassist強(qiáng)大的API下,實(shí)現(xiàn)起來(lái)還是蠻簡(jiǎn)單的。
在接下來(lái)的一段時(shí)間里,冰河會(huì)持續(xù)輸出關(guān)于字節(jié)碼編程的文章,讓我們一起精通字節(jié)碼編程。
好了,今天就到這兒吧,我是冰河,我們下期見~~
本文轉(zhuǎn)載自微信公眾號(hào)「冰河技術(shù)」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系冰河技術(shù)公眾號(hào)。