反射工具包(字节码生成)
程序员文章站
2022-05-07 10:30:17
...
ReflectionUtil
反射工具包,利用反射的API直接生成Java字节码,提高执行效率。
普通方法调用
所有的命令最终生成到Invoker对象的invoke方法中
public Object invoke(Object[] args);
具体使用如下:
InvokerBuilder builder=InvokerBuilder.getInstance(); Method concat = String.class.getMethod("concat", new Class[]{String.class}); Method println = PrintStream.class.getMethod("println", new Class[]{String.class}); builder.constant("hello") //定义常量 .store("end") //赋值给变量end 以上两句相当于String end = "hello" .methodInvoke(concat, Ops.$(0), Ops.v("end")) //调用invoke方法参数数组中的第0个值的concat方法,参数为变量end .store("tt")//将以上方法的返回值赋值给tt .staticField(System.class, "out") //获取System.out对象 .constant("hello world!") //定义常量 .methodInvoke(println) //调用Sytem.out的println对象 .ret("tt"); //返回tt
以上的所有操作,相当于直接编写以下代码
public class Generate$2055281021 implements Invoker { public Object invoke(Object[] paramArrayOfObject) { String str1 = "hello"; String str2 = ((String)paramArrayOfObject[0]).concat(str1); System.out.println("hello world!"); return str2; } }
创建对象
直接调用new创建 具体代码如下:
InvokerBuilder builder=InvokerBuilder.getInstance(); Constructor<StringBuilder> init=StringBuilder.class.getConstructor(String.class); Method append = StringBuilder.class.getMethod("append", String.class); Method toString=Object.class.getMethod("toString", new Class[]{}); builder.constant("hello") //定义常量 .store("a") //赋值给变量a .newInstance(StringBuilder.class, init,Ops.v("a")) //调用new指令,创建对象同时调用构造函数 .store("sb")//赋值给sb变量 .constant("world")//定义常量"world" .store("t") //赋值给变量t .methodInvoke(append, Ops.v("sb"), Ops.v("t")) //调用append方法 .methodInvoke(toString) //调用toString .ret(); //返回以上调用的结果
以上所有操作相当于直接编写以下代码:
public class Generate$918221580 implements Invoker { public Object invoke(Object[] paramArrayOfObject) { String str1 = "hello"; StringBuilder localStringBuilder = new StringBuilder(str1); String str2 = "world"; return localStringBuilder.append(str2).toString(); } }
注意:在调用newInstance时,会同时调用构造方法和dup指令(将新对象的引用复制一份到栈顶),如果仅仅是调用构造方法而不使用新生成的对象(复制或作为方法的参数等),在调用完newInstance后要执行pop操作。
dump及写文件
编写完所有指令后,可以将字节码dump成jvm指令或写入文件中。使用如下:
InvokerBuilder builder=InvokerBuilder.getInstance(); Method concat = String.class.getMethod("concat", new Class[]{String.class}); builder.constant("hello").constant("world").methodInvoke(concat).ret(); ByteArrayOutputStream bos=new ByteArrayOutputStream(); builder.dump(bos); System.out.println(new String(bos.toByteArray())); builder.store2file("d:/tt/ttt1.class");
输出如下:
public class org.cc.Generate$918221580 extends java.lang.Object implements org.cc.common.reflection.core.Invoker{ public org.cc.Generate$918221580(); Code: 0: aload_0 1: invokespecial #10; //Method java/lang/Object."<init>":()V 4: return public java.lang.Object invoke(java.lang.Object[]); Code: 0: ldc #14; //String hello 2: ldc #16; //String world 4: invokevirtual #22; //Method java/lang/String.concat:(Ljava/lang/String;)Ljava/lang/String; 7: areturn }
github地址:https://github.com/DreamLee471/ReflectionUtil
更多使用参见sample
有任何疑问可直接发邮件到dreamlee471@gmail.com
推荐阅读
-
JDK动态代理之ProxyGenerator生成代理类的字节码文件解析
-
Java中反射获取字节码的三种方式
-
jvm第9节-asm生成class字节码
-
jvm第9节-asm生成class字节码
-
反射工具包(字节码生成)
-
反射工具包(字节码生成)
-
ASM系列五 利用TreeApi 解析生成Class ASM字节码动态生成TreeAPIClassNode
-
ASM系列一 利用Core API 解析和生成字节码 javaAOPASM
-
ASM系列三 利用Methord组件动态生成方法字节码 ASMJava动态代理字节码技术动态生成字节码
-
ASM系列二 利用Core API 迁移、添加及移除类成员 ASM字节码动态生成技术AOP