java----字节码操作
Java动态性的两种常见方式
-反射
-字节码操作:所谓字节码操作就是当xx.class文件被加载到虚拟机后,我们可以使用类库来操作这些字节码
运行时操作字节码可以让我们实现如下功能
-动态生成新的类
-动态改变某个类的结构(添加/删除/修改新的属性/方法
优势:
-比反射开销小,性能高。
-JAVAasist性能高于反射,低于ASM
常见的字节码操作类库
BCEL
ASM
CGLIB(Code Generation Library)
Javassist
Javassist使用
如果需要详细了解:可以下载框架
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();
}
操作已经存在的类
1、给存在的.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();
}
}
2、通过字节码实现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();
}
}

浙公网安备 33010602011771号