java----字節碼操做

Java動態性的兩種常見方式

  -反射java

  -字節碼操做:所謂字節碼操做就是當xx.class文件被加載到虛擬機後,咱們可使用類庫來操做這些字節碼編程

運行時操做字節碼可讓咱們實現以下功能 

  -動態生成新的類
  -動態改變某個類的結構(添加/刪除/修改新的屬性/方法框架

優點:

  -比反射開銷小,性能高。
  -JAVAasist性能高於反射,低於ASMmaven

常見的字節碼操做類庫

  BCEL性能

  ASMthis

  CGLIB(Code Generation Library)spa

  Javassist代理

Javassist使用

若是須要詳細瞭解:能夠下載框架code

maven依賴jar包對象

<!-- https://mvnrepository.com/artifact/org.javassist/javassist -->
<dependency>
    <groupId>org.javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.25.0-GA</version>
</dependency>

簡單使用

字節碼不能操做對象,若是須要操做對象還須要藉助反射

建立新類

public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, ScriptException, CannotCompileException, NotFoundException {
        //得到類池
        ClassPool aDefault = ClassPool.getDefault();

        //建立類的名字 能夠指定包名 例如:com.zy.Dog
        CtClass ctClass = aDefault.makeClass("Dog");

        //添加屬性(能夠new CtField,和添加方法相似(在test01中說起))
        CtField public_int_age = CtField.make("public int age;", ctClass);
        CtField public_string_like= CtField.make("public String like;", ctClass);
        ctClass.addField(public_int_age);
        ctClass.addField(public_string_like);

        //添加方法
        CtMethod test = CtMethod.make("public void test(){System.out.println(\"添加成功\");}", ctClass);
        ctClass.addMethod(test);

        //添加構造器
        CtConstructor ctConstructor = new CtConstructor(new CtClass[]{CtClass.intType,aDefault.get("java.lang.String")}, ctClass);
        ctConstructor.setBody("{this.age=$1;this.like=$2;}");
        ctClass.addConstructor(ctConstructor);

        //開始建立一個Dog.class文件,能夠指定Dog.class文件路徑
        ctClass.writeFile();
    }

操做已經存在的類

一、給存在的.class文件追加方法.讓對象去執行這個方法

public static void test01(){
        try {
            ClassPool aDefault = ClassPool.getDefault();
            CtClass ctClass = aDefault.get("com.zy.Dog");
            //byte[] bytes = ctClass.toBytecode();
            //獲取類名
            System.out.println(ctClass.getName());
            //獲取簡單類名
            System.out.println(ctClass.getSimpleName());

            //添加方法
            //CtMethod test1 = CtMethod.make("public void test(int a,int b){System.out.println(\"添加成功\");}", ctClass);
            //另外一種添加方法的方式
            CtMethod ctMethod = new CtMethod(CtClass.intType, "t", new CtClass[]{CtClass.intType,CtClass.intType}, ctClass);
            ctMethod.setModifiers(Modifier.PUBLIC);
            ctMethod.setBody("return $1+$2;");
            ctClass.addMethod(ctMethod);

            //經過反射調用方法
            Class<?> aClass = ctClass.toClass();
            Method test = aClass.getDeclaredMethod("t",int.class,int.class);
            //對象0能夠是外部傳遞進來,此時test方法就是一個代理方法
            Object o = aClass.getConstructor().newInstance();
            Object invoke = test.invoke(o, 1,1);
            System.out.println(invoke);
        } catch (NotFoundException e) {
            e.printStackTrace();
        } catch (CannotCompileException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }

二、經過字節碼實現AOP編程

此時test02必須是一個代理類的方法。咱們將本身的對象經過test02傳遞進去

public static void test02(){
        try {
            ClassPool aDefault = ClassPool.getDefault();
            CtClass ctClass = aDefault.get("com.zy.Dog");
            CtMethod play = ctClass.getDeclaredMethod("play");
            //能夠對已經存在的方法進行修改
            //play.setBody("System.out.println(\"Dog沒有play\");");
            //執行方法以前能夠執行其餘的方法;
            play.insertBefore("System.out.println(\"Dog在吃東西\");");
            
            //反射執行該方法
            Class<?> aClass = ctClass.toClass();
            Method test = aClass.getDeclaredMethod("play");
            Object o = aClass.getConstructor().newInstance();
            Object invoke = test.invoke(o);
        } catch (NotFoundException e) {
            e.printStackTrace();
        } catch (CannotCompileException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
相關文章
相關標籤/搜索