日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

JVM Class字节码之三-使用BCEL改变类属性

發布時間:2025/3/21 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JVM Class字节码之三-使用BCEL改变类属性 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

使用BCEL動態改變Class內容

之前對Class文件中的常量池,Method的字節碼指令進行了說明。
JVM Class詳解之一
JVM Class詳解之二 Method字節碼指令
現在我們開始實際動手,使用BCEL改變字節碼指令,對Class文件進行功能擴充。

先介紹下BCEL全程Apache Byte Code Engineering Library,BCEL 每項內容操作在JVM匯編語言的級別

HelloWorld搞起

這個case我們需要給Programmer類做功能擴展,Programmer 職責進行了變化,除了要Coding以外,在每次Coding之前需要先做Plan,所以需要在do Coding信息輸出之前輸出 "doBcelPlan..." 信息。
Demo

public class Programmer implements Person {@Overridepublic void doCoding() {System.out.println("do Coding...");}}

期望效果

@Overridepublic void doCoding() {doPlan();System.out.println("do Coding...");}private void doPlan() {System.out.println("do Plan...");}

需要做什么

針對我們的期望結果我們需要做以下三點

  • 增加一個doBcelPlan方法
  • 在doCoding方法中調用doBcelPlan方法
  • 在常量池中加入方法的聲明,常量等其它使用到的變量和方法。
  • 工程先引入BCEL的依賴Pom中追加即可

    <dependency><groupId>asm</groupId><artifactId>asm</artifactId><version>3.1</version></dependency><dependency><groupId>asm</groupId><artifactId>asm-tree</artifactId><version>3.1</version></dependency>

    1. 先使用BCEL 加載需要編輯的Class

    JavaClass clazz = Repository.lookupClass(Programmer.class);ClassGen classGen = new ClassGen(clazz);ConstantPoolGen cPoolGen = classGen.getConstantPool(); // 常量池信息

    2. 在常量池中增加一個MethodRef doBcelPlan

    int methodIndex = cPoolGen.addMethodref("byteCode.decorator.Programmer", "doBcelPlan", "()V"); // 在常量池中增加一個方法的聲明返回methodIndex為聲明在常量池中的位置索引

    第一個參數的去路徑類名
    第二個參數是方法名稱
    第三個方法返回類型 ()V 是void類型
    方法返回類型描述參考

    3. 在常量池中增加一個String類型的Filed

    因為有System.out.println("doBcelPlan")語句?
    doBcelPlan中的System.out 變量和println方法再doCoding中已經使用所有已經在常量池中了

    int stringIndex = cPoolGen.addString("doBcelPlan...");// 在常量池中增加一個Field的聲明返回stringIndex為聲明在常量池中的位置索引

    注意這里需要記錄追加方法和Filed的index后面需要使用。

    4. 然后創建doBcelPlan方法的實體的字節碼指令

    調用System.out變量和println方法 具體的字節碼指令參數 上一節內容有說明 參考上一節文檔?JVM Class詳解之二 Method字節碼指令

    InstructionList instructionDoPlan = new InstructionList(); // 字節碼指令信息 instructionDoPlan.append(new GETSTATIC(17)); // 獲取System.out常量 instructionDoPlan.append(new LDC(stringIndex)); // 獲取String Field信息 instructionDoPlan.append(new INVOKEVIRTUAL(25)); // 調用Println方法 instructionDoPlan.append(new RETURN()); // return 結果


    其中17,25都是常量池的引用參見下圖,將原先的Programmer類編譯后使用javap -versobse XXX.class 可以查看常量池信息。

    stringIndex 是引用第三步追加常量池String Field soBcelPlan

    5. 生成doBcelPlan方法

    MethodGen doPlanMethodGen = new MethodGen(1, Type.VOID, Type.NO_ARGS, null, "doBcelPlan", classGen.getClassName(), instructionDoPlan, cPoolGen); classGen.addMethod(doPlanMethodGen.getMethod());

    方法的聲明并追加到classGen中。
    這樣doBcelPlan方法就追加成功了。接下來我們需要找到doCoding方法,在方法中追加doBcelPlan的調用。

    6. 找到并修正doCoding方法

    Method[] methods = classGen.getMethods();for (Method method : methods) {String methodName = method.getName();if ("doCoding".equals(methodName)) {MethodGen methodGen = new MethodGen(method, clazz.getClassName(), cPoolGen);InstructionList instructionList = methodGen.getInstructionList();InstructionHandle[] handles = instructionList.getInstructionHandles();InstructionHandle from = handles[0];InstructionHandle aload = instructionList.append(from, new ALOAD(0));instructionList.append(aload, new INVOKESPECIAL(methodIndex));classGen.replaceMethod(method, methodGen.getMethod());}}

    InstructionList 是當前方法中的字節碼指令,我們append了兩個指令ALOAD和INVOKESPECIAL。實現doBcelPlan的調用。

    7. 將編輯后的Class輸出

    JavaClass target = classGen.getJavaClass();target.dump("D:\\AliDrive\\bytecode\\bcel\\Programmer.class");

    將修改后的字節碼輸出來看下,使用JD打開OK

    可以看到經過編輯后的Class文件輸出結果同我們預期的是一樣的
    Done!


    from:?https://yq.aliyun.com/articles/7243?spm=5176.100239.blogcont7241.37.db8GKF

    總結

    以上是生活随笔為你收集整理的JVM Class字节码之三-使用BCEL改变类属性的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。