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);
复制代码
相关文章
相关标签/搜索