JAVA動態字節碼

概述

java動態字節碼指的是在java字節碼生成以後,對其進行修改,加強其功能,這種方式至關於對代碼的二進制文件進行修改。動態java字節碼主要是爲了減小冗餘代碼,提升性能。java

實現字節碼加強的主要步驟:數組

  1. 修改字節碼。在內存中獲取到原來的字節碼,經過一些工具(如ASMJavaasist)來修改它的byte[]數組,獲得一個新的byte[]數組。
  2. 使修改後的字節碼生效
    1. 自定義ClassLoader來加載修改後的字節碼
    2. 替換掉原來的字節碼,在JVM加載用戶的Class時,攔截返回修改後的字節碼。

用途bash

  1. 動態生成新的類
  2. 動態修改某個類的結構(添加/刪除/修改 新的屬性/方法)
  3. AOP技術使用的就是動態字節碼技術

字節碼操做類庫

BCEL

BCEL能夠深刻JVM彙編語言進行類操做的細節。BCELjavassist有不一樣的處理字節碼方法,BCEL在實際的JVM指令層次上進行操做,而javassist所強調的是源代碼級別的工做。框架

ASM

是輕量級java字節碼操做框架,直接涉及到JVM底層的操做和指令。高性能,高質量maven

CGLB

基於ASM實現工具

javassist

性能低於ASMCGLB差很少,可是使用簡單,不少開源框架都使用的是javassistjavassist比反射開銷小,性能高。性能

javassist的最外層的APIJAVA的反射包中的API頗爲類似。它主要由CtClassCtMethod以及CtField幾個類組成,用以執行和JDK反射APIjava.lang.Classjava.lang.reflect.Methodjava.lang.reflect.Field相同的操做。ui

侷限性this

  1. JDK5.0新語法不支持(包括泛型、枚舉),不支持註解修改
  2. 不支持數組的初始化
  3. 不支持內部類和匿名類
  4. 不支持continuebreak表達式
  5. 對於繼承關係,有些不支持。

maven : mvnrepository.com/artifact/ja…spa


反射調用方法

public class User {

    private String name;
    private Integer age;


    public void sum(int a,int b){
        int sum = a + b;
        System.out.println("sum = " + sum);
    }


    public static void main(String[] args) {
        try {
            Class<?> clz = Class.forName("javassist.User");
            Object newInstance = clz.newInstance();
            Method method = clz.getDeclaredMethod("sum", int.class, int.class);
            Object invoke = method.invoke(newInstance, 1, 3);

        }catch (Exception e){

        }
    }
}
複製代碼

javassist生成class文件

//使用javassist建立class文件
 ClassPool pool = ClassPool.getDefault();
 //建立 class 文件
 CtClass userClass = pool.makeClass("com.beisiji.javassist.User");
 //建立 id 屬性
 CtField idField = CtField.make("private Integer id;", userClass);
 //建立 name 屬性
 CtField nameField = CtField.make("private String name;", userClass);
 //添加屬性
 userClass.addField(idField);
 userClass.addField(nameField);
 //建立方法
 CtMethod setIdMethod = CtMethod.make("public void setId(Integer id) { this.id = id; }", userClass);
 CtMethod getIdMethod = CtMethod.make("public Integer getId() { return id; }", userClass);
 //添加方法
 userClass.addMethod(setIdMethod);
 userClass.addMethod(getIdMethod);

//建立構造器
CtConstructor ctConstructor = new CtConstructor(new CtClass[]{CtClass.intType, pool.get("java.lang.String")}, userClass);
ctConstructor.setBody("{ this.id = id;this.name = name; }");
userClass.addConstructor(ctConstructor);
userClass.writeFile("C:/Users/yuanl/Desktop/md_dir");
複製代碼

javassist修改類文件信息

//使用javassist修改類文件信息(添加方法)
 ClassPool pool = ClassPool.getDefault();
 //須要加載的類信息(須要修改類信息的全限定名稱)
 CtClass userClass = pool.get("executor.ExecutorDemo");
 //建立方法
 CtMethod method = new CtMethod(CtClass.intType, "add", new CtClass[]{CtClass.intType, CtClass.intType}, userClass);
 //設置方法權限
 method.setModifiers(Modifier.PUBLIC);
 method.setBody("{return $1 + $2;}");	//$0:this , $1第一個參數 , $2第二個參數
 userClass.addMethod(method);
 userClass.writeFile("C:/Users/yuanl/Desktop/md_dir");
 
 //調用添加的方法
 Class clz = userClass.toClass();
 Object newInstance = clz.newInstance();
 Method addMethod = clz.getDeclaredMethod("add", int.class, int.class);
 Object invoke = addMethod.invoke(newInstance, 2, 3);
 System.out.println("invoke = " + invoke);
複製代碼
相關文章
相關標籤/搜索