<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          大哥,你的Java字節(jié)碼需要增強(qiáng)下

          共 8371字,需瀏覽 17分鐘

           ·

          2021-08-06 06:10

          點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號”

          優(yōu)質(zhì)文章,第一時(shí)間送達(dá)

          簡單介紹下幾種java字節(jié)碼增強(qiáng)技術(shù)。

          ASM

          ASM是一個(gè)Java字節(jié)碼操控框架,它能被用來動(dòng)態(tài)生成類或者增強(qiáng)既有類的功能。ASM可以直接產(chǎn)生class文件,也可以在類被加載入Java虛擬機(jī)之前動(dòng)態(tài)改變類行為。ASM從類文件中讀入信息后,能夠改變類行為,分析類信息,甚至能夠根據(jù)用戶要求生成新類。

          主頁:https://asm.ow2.io/index.html

          ASM框架中的核心類有以下幾個(gè):

           ?、?nbsp; ClassReader:該類用來解析編譯過的class字節(jié)碼文件。

           ?、?nbsp; ClassWriter:該類用來重新構(gòu)建編譯后的類,比如說修改類名、屬性以及方法,甚至可以生成新的類的字節(jié)碼文件。

           ?、?nbsp; ClassAdapter:該類也實(shí)現(xiàn)了ClassVisitor接口,它將對它的方法調(diào)用委托給另一個(gè)ClassVisitor對象。

          參考代碼:

          import java.io.File;
          import java.io.FileNotFoundException;
          import java.io.FileOutputStream;
          import java.io.IOException;

          import org.objectweb.asm.ClassWriter;
          import org.objectweb.asm.Opcodes;

          public class GeneratorClass {

              public static void main(String[] args) throws IOException {
                  //生成一個(gè)類只需要ClassWriter組件即可
                  ClassWriter cw = new ClassWriter(0);
                  //通過visit方法確定類的頭部信息
                  cw.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC+Opcodes.ACC_ABSTRACT+Opcodes.ACC_INTERFACE,
                          "com/asm3/Comparable", null, "java/lang/Object", new String[]{"com/asm3/Mesurable"});
                  //定義類的屬性
                  cw.visitField(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL+Opcodes.ACC_STATIC,
                          "LESS""I", null, new Integer(-1)).visitEnd();
                  cw.visitField(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL+Opcodes.ACC_STATIC,
                          "EQUAL""I", null, new Integer(0)).visitEnd();
                  cw.visitField(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL+Opcodes.ACC_STATIC,
                          "GREATER""I", null, new Integer(1)).visitEnd();
                  //定義類的方法
                  cw.visitMethod(Opcodes.ACC_PUBLIC+Opcodes.ACC_ABSTRACT, "compareTo",
                          "(Ljava/lang/Object;)I", null, null).visitEnd();
                  cw.visitEnd(); //使cw類已經(jīng)完成
                  //將cw轉(zhuǎn)換成字節(jié)數(shù)組寫到文件里面去
                  byte[] data = cw.toByteArray();
                  File file = new File("D://Comparable.class");
                  FileOutputStream fout = new FileOutputStream(file);
                  fout.write(data);
                  fout.close();
              }
          }

          Javassist

          Javassist是一個(gè)開源的分析、編輯和創(chuàng)建Java字節(jié)碼的類庫。

          它已加入了開放源代碼JBoss應(yīng)用服務(wù)器項(xiàng)目,通過使用Javassist對字節(jié)碼操作為JBoss實(shí)現(xiàn)動(dòng)態(tài)"AOP"框架。

          主頁:http://www.javassist.org/

          利用Javassist實(shí)現(xiàn)字節(jié)碼增強(qiáng)時(shí),可以無須關(guān)注字節(jié)碼刻板的結(jié)構(gòu),其優(yōu)點(diǎn)就在于編程簡單。直接使用java編碼的形式,而不需要了解虛擬機(jī)指令,就能動(dòng)態(tài)改變類的結(jié)構(gòu)或者動(dòng)態(tài)生成類。其中最重要的是ClassPool、CtClass、CtMethod、CtField這四個(gè)類:

          • CtClass(compile-time class):編譯時(shí)類信息,它是一個(gè)class文件在代碼中的抽象表現(xiàn)形式,可以通過一個(gè)類的全限定名來獲取一個(gè)CtClass對象,用來表示這個(gè)類文件。

          • ClassPool:從開發(fā)視角來看,ClassPool是一張保存CtClass信息的HashTable,key為類名,value為類名對應(yīng)的CtClass對象。當(dāng)我們需要對某個(gè)類進(jìn)行修改時(shí),就是通過pool.getCtClass(“className”)方法從pool中獲取到相應(yīng)的CtClass。

          • CtMethod、CtField:這兩個(gè)比較好理解,對應(yīng)的是類中的方法和屬性。

          參考代碼:

          import javassist.*;

          public class CreatePerson {

              public static void createPseson() throws Exception {
                  ClassPool pool = ClassPool.getDefault();

                  // 1. 創(chuàng)建一個(gè)空類
                  CtClass cc = pool.makeClass("com.test.javassist.Person");

                  // 2. 新增一個(gè)字段 private String name;
                  // 字段名為name
                  CtField param = new CtField(pool.get("java.lang.String"), "name", cc);
                  // 訪問級別是 private
                  param.setModifiers(Modifier.PRIVATE);
                  // 初始值是 "xiaoming"
                  cc.addField(param, CtField.Initializer.constant("xiaoming"));

                  // 3. 生成 getter、setter 方法
                  cc.addMethod(CtNewMethod.setter("setName", param));
                  cc.addMethod(CtNewMethod.getter("getName", param));

                  // 4. 添加無參的構(gòu)造函數(shù)
                  CtConstructor cons = new CtConstructor(new CtClass[]{}, cc);
                  cons.setBody("{name = \"xiaohong\";}");
                  cc.addConstructor(cons);

                  // 5. 添加有參的構(gòu)造函數(shù)
                  cons = new CtConstructor(new CtClass[]{pool.get("java.lang.String")}, cc);
                  // $0=this / $1,$2,$3... 代表方法參數(shù)
                  cons.setBody("{$0.name = $1;}");
                  cc.addConstructor(cons);

                  // 6. 創(chuàng)建一個(gè)名為printName方法,無參數(shù),無返回值,輸出name值
                  CtMethod ctMethod = new CtMethod(CtClass.voidType, "printName", new CtClass[]{}, cc);
                  ctMethod.setModifiers(Modifier.PUBLIC);
                  ctMethod.setBody("{System.out.println(name);}");
                  cc.addMethod(ctMethod);

                  //這里會將這個(gè)創(chuàng)建的類對象編譯為.class文件
                  cc.writeFile("/Users/yangyue/workspace/springboot-learn/java-agent/src/main/java/");
              }

              public static void main(String[] args) {
                  try {
                      createPseson();
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
              }
          }

          Byte Buddy

          Byte Buddy是一個(gè)代碼生成和操作庫,用于在Java應(yīng)用程序運(yùn)行時(shí)創(chuàng)建和修改Java類,而無需編譯器的幫助。
          除了Java類庫附帶的代碼生成實(shí)用程序外,Byte Buddy還允許創(chuàng)建任意類,并且不限于實(shí)現(xiàn)用于創(chuàng)建運(yùn)行時(shí)代理的接口。
          此外,Byte Buddy提供了一種方便的API,可以使用Java代理或在構(gòu)建過程中手動(dòng)更改類。

          主頁:https://bytebuddy.net/#/

          參考代碼:

          Class<?> dynamicType = new ByteBuddy()
            .subclass(Object.class)
            .method(ElementMatchers.named("toString"))
            .intercept(FixedValue.value("Hello World!"))
            .make()
            .load(getClass().getClassLoader())
            .getLoaded();
           
          assertThat(dynamicType.newInstance().toString(), is("Hello World!"));

          JVM-SANDBOX

          JVM沙箱容器,一種JVM的非侵入式運(yùn)行期AOP解決方案:

          1. 動(dòng)態(tài)增強(qiáng)類你所指定的類,獲取你想要的參數(shù)和行信息甚至改變方法執(zhí)行。

          2. 動(dòng)態(tài)可插拔容器框架。



            作者 |  阿凡盧

          來源 |  cnblogs.com/luxiaoxun/p/15075778.html


          加鋒哥微信: java3459  
          圍觀鋒哥朋友圈,每天推送Java干貨!

          瀏覽 73
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日本香港台湾三级无码 | 国产伦精品一区二区三区视频女 | 天天干干天天 | 性一乱一交一交一视频 | 日本一区二区在线 |