asm在解析文件的时候是按照特定顺序进行分析的,首先是visit方法,做类相关的解析,然后是注解,然后是属性,最后才是方法,属性是在所有方法分析前面进行,也就是只有当class文件中的所有属性都遍历完毕之后,才会去遍历方法
1.自定义类加载器
package club.jiajia.test;
public class MyClassLoader extends ClassLoader{
public Class<?> defineClassByName(String name,byte[] b,int off,int len){
Class<?> clazz = super.defineClass(name,b, off, len);
return clazz;
}
}
2.asm动态生成字节码
package club.jiajia.test2;
import java.util.List;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
/**
* jiajiajia
*/
public class Asm implements Opcodes {
public byte[] createBeanClass(String className, List<FieldInfo> fields) {
ClassWriter cw = new ClassWriter(0);
cw.visit(V1_1, ACC_PUBLIC, className, null, "java/lang/Object", null);
// creates a MethodWriter for the (implicit) constructor
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
mv.visitInsn(RETURN);
mv.visitMaxs(1, 1);
for (FieldInfo f : fields) {
addMethod(cw, mv, className, f);
}
return cw.toByteArray();
}
private void addMethod(ClassWriter cw, MethodVisitor mv, String className,
FieldInfo fieldInfo) {
String fieldName = fieldInfo.name;
String setMethodName = "set" +fieldName;
String getMethodName = "get" +fieldName;
String typeof = Type.getType(fieldInfo.type).getDescriptor();
String getof = getof(typeof);
String setof = setof(typeof);
int[] loadAndReturnOf = loadAndReturnOf(typeof);
//add field
cw.visitField(ACC_PRIVATE, fieldName, typeof, null, 0).visitEnd();
// getMethod
mv = cw.visitMethod(ACC_PUBLIC, getMethodName, getof, null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, className, fieldName, typeof);
mv.visitInsn(loadAndReturnOf[1]);
mv.visitMaxs(2, 1);
mv.visitEnd();
// setMethod
mv = cw.visitMethod(ACC_PUBLIC, setMethodName, setof, null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(loadAndReturnOf[0], 1);
mv.visitFieldInsn(PUTFIELD, className, fieldName, typeof);
mv.visitInsn(RETURN);
mv.visitMaxs(3, 3);
mv.visitEnd();
}
private String setof(String typeof) {
return "(" + typeof + ")V";
}
private String getof(String typeof) {
return "()" + typeof;
}
private int[] loadAndReturnOf(String typeof) {
if (typeof.equals("I") || typeof.equals("Z")) {
return new int[]{ILOAD,IRETURN};
} else if (typeof.equals("J")) {
return new int[]{LLOAD,LRETURN};
} else if (typeof.equals("D")) {
return new int[]{DLOAD,DRETURN};
} else if (typeof.equals("F")) {
return new int[]{FLOAD,FRETURN};
} else {
return new int[]{ALOAD,ARETURN};
}
}
}
3.定义属性信息
package club.jiajia.test2;
public class FieldInfo {
public Class<?> clazz;
public String name;
public String type;
public Object value;
public FieldInfo(Class<?> clazz, String name, Object value) {
super();
this.clazz = clazz;
this.name = name;
this.value = value;
}
}
4.测试
package club.jiajia.test2;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import club.jiajia.test.MyClassLoader;
/**
* jiajiajia
*/
public class Test extends ClassLoader {
private static String className="Abc";
private static List<FieldInfo> fields;
public static byte[] setUp(){
FieldInfo testString = new FieldInfo(int.class, "name", 1);
testString.type="I";
fields = new ArrayList<FieldInfo>();
fields.add(testString);
return new Asm().createBeanClass(className, fields);
}
public static void main(String[] args) {
byte b[]=setUp();
MyClassLoader mcl=new MyClassLoader();
//返回的对象时被加载类的class
Class<?> hw=mcl.defineClassByName("Abc", b, 0, b.length);
try {
//利用反射创建对象
Object o= hw.newInstance();
java.lang.reflect.Method method= o.getClass().getMethod("getname");
java.lang.reflect.Method method2= o.getClass().getMethod("setname",int.class);
method2.invoke(o,3);
System.out.println(method.invoke(o));
}catch (Exception e) {
e.printStackTrace();
}
File file = new File("E://jiajiajia/Abc.class");
try {
FileOutputStream fout = new FileOutputStream(file);
fout.write(b);
fout.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
5.测试结果
测试的时候会在E://jiajiajia文件夹下生成一个Abc.clss文件
6.反编译结果为:
public class Abc
{
private int name = 0;
public int getname() {
return this.name;
}
public void setname(final int name) {
this.name = name;
}
}
7.测试2
生成if条件判断
package club.jiajia.test3;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
public class TestAsm implements Opcodes{
public static void main(String[] args) throws InstantiationException, IllegalAccessException{
ClassWriter cw=new ClassWriter(0);
String className="Example";
cw.visit(0x31,ACC_PUBLIC,className,null,"java/lang/Object",new String[]{"java/lang/Cloneable",ITest.class.getName().replace('.','/')});
String field="test";
String a="a";
Object defaultValue=123d;
Object defaultValues=1123;
String setMd="setTest";
String getMd="getTest";
String getMa="getMa";
cw.visitField(ACC_PRIVATE,field,"D",null,defaultValue == null?null:Double.parseDouble(defaultValue.toString())).visitEnd();
cw.visitField(ACC_PRIVATE,a,"I",null,defaultValues == null?null:Double.parseDouble(defaultValues.toString())).visitEnd();
MethodVisitor mv=cw.visitMethod(ACC_PUBLIC,getMd,"()D",null,null);
mv.visitCode();
mv.visitVarInsn(ALOAD,0);
mv.visitFieldInsn(GETFIELD,className,field,"D");
mv.visitInsn(DRETURN);
mv.visitMaxs(2,2);
mv.visitEnd();
cw.visitEnd();
mv=cw.visitMethod(ACC_PUBLIC,setMd,"(D)V",null,null);
mv.visitCode();
mv.visitVarInsn(ALOAD,0);
/**
* 访问本地变量指令。本地变量指令是ar *指令,它加载或存储本地变量* @param的值。这个操作码是ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE或RET.* @param vanthe操作数的指令访问。这个操作数是一个局部变量的索引
*/
mv.visitVarInsn(DLOAD,1);
mv.visitFieldInsn(PUTFIELD,className,field,"D");
mv.visitInsn(RETURN);
mv.visitMaxs(3,3);
mv.visitEnd();
/***********************************************************/
mv=cw.visitMethod(ACC_PUBLIC,getMa,"(I)V",null,null);
mv.visitCode();
mv.visitVarInsn(ILOAD, 1);
Label label = new Label();
mv.visitJumpInsn(IFLT, label);
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ILOAD, 1);
mv.visitFieldInsn(PUTFIELD, className, "a", "I");
Label end = new Label();
mv.visitJumpInsn(GOTO, end);
mv.visitLabel(label);
mv.visitFrame(F_SAME, 0, null, 0, null);
mv.visitTypeInsn(NEW, "java/lang/IllegalArgumentException");
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL,
"java/lang/IllegalArgumentException", "<init>", "()V");
mv.visitInsn(ATHROW);
mv.visitLabel(end);
mv.visitFrame(F_SAME, 0, null, 0, null);
mv.visitInsn(RETURN);
mv.visitMaxs(2, 2);
mv.visitEnd();
/***********************************************************/
//下面产生构造方法
mv=cw.visitMethod(ACC_PUBLIC,"<init>","()V",null,null);
mv.visitCode();
mv.visitVarInsn(ALOAD,0);
mv.visitMethodInsn(INVOKESPECIAL,"java/lang/Object","<init>","()V");
mv.visitInsn(RETURN);
mv.visitMaxs(1,1);
mv.visitEnd();
cw.visitEnd();
byte[] bs=cw.toByteArray();
File file = new File("E://jiajiajia/Example.class");
try {
FileOutputStream fout = new FileOutputStream(file);
fout.write(bs);
fout.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
MyCLassLoader loader=new MyCLassLoader();
Class<?> c=loader.defineClass(bs);
ITest ins=(ITest)c.newInstance();
ins.setTest(100.0d);
ins.getMa(-2);
System.out.println(ins.getTest());
}
public interface ITest{
public double getTest();
public void setTest(double d);
public void getMa(int a);
}
public static class MyCLassLoader extends ClassLoader{
public Class defineClass(byte[] data){
return super.defineClass(null,data,0,data.length,null);
}
}
}
反编译结果为
import club.jiajia.test3.*;
public class Example implements Cloneable, TestAsm$ITest
{
private double test = 123.0;
private int a = 1123;
public double getTest() {
return this.test;
}
public void setTest(final double test) {
this.test = test;
}
public void getMa(final int i) {
while (i < 0) {}
this.a = i;
}
}
8.生成更为复杂的方法
package club.jiajia.test3;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
public class TestAsm2 implements Opcodes{
public static void main(String[] args) throws InstantiationException, IllegalAccessException{
ClassWriter cw=new ClassWriter(0);
String className="Example2";
cw.visit(0x31,ACC_PUBLIC,className,null,"java/lang/Object",new String[]{"java/lang/Cloneable",ITest.class.getName().replace('.','/')});
String a="a";
Object av=123;
String getA="getA";
String setA="setA";
cw.visitField(ACC_PRIVATE,a,"I",null,av == null?null:Integer.parseInt(av.toString())).visitEnd();
MethodVisitor mv=cw.visitMethod(ACC_PUBLIC,getA,"()I",null,null);
mv.visitCode();
mv.visitVarInsn(ALOAD,0);
mv.visitFieldInsn(GETFIELD,className,a,"I");
mv.visitInsn(IRETURN);
mv.visitMaxs(2,2);
mv.visitEnd();
cw.visitEnd();
/***********************************************************/
mv=cw.visitMethod(ACC_PUBLIC,setA,"(II)V",null,null);
mv.visitCode();
mv.visitVarInsn(ILOAD, 1);
mv.visitVarInsn(ILOAD, 2);
Label label = new Label();
mv.visitJumpInsn(IF_ICMPLT, label);
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ILOAD, 1);
mv.visitFieldInsn(PUTFIELD, className, "a", "I");
Label end = new Label();
mv.visitJumpInsn(GOTO, end);
mv.visitLabel(label);
mv.visitFrame(F_SAME, 0, null, 0, null);
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ILOAD, 2);
mv.visitFieldInsn(PUTFIELD, className, "a", "I");
mv.visitLabel(end);
mv.visitFrame(F_SAME, 0, null, 0, null);
mv.visitInsn(RETURN);
mv.visitMaxs(3, 3);
mv.visitEnd();
/***********************************************************/
//下面产生构造方法
mv=cw.visitMethod(ACC_PUBLIC,"<init>","()V",null,null);
mv.visitCode();
mv.visitVarInsn(ALOAD,0);
mv.visitMethodInsn(INVOKESPECIAL,"java/lang/Object","<init>","()V");
mv.visitInsn(RETURN);
mv.visitMaxs(1,1);
mv.visitEnd();
cw.visitEnd();
byte[] bs=cw.toByteArray();
File file = new File("E://jiajiajia/Example2.class");
try {
FileOutputStream fout = new FileOutputStream(file);
fout.write(bs);
fout.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
MyCLassLoader loader=new MyCLassLoader();
Class<?> c=loader.defineClass(bs);
ITest ins=(ITest)c.newInstance();
ins.setA(145,12);
System.out.println(ins.getA());
}
public interface ITest{
public int getA();
public void setA(int a,int b);
}
public static class MyCLassLoader extends ClassLoader{
public Class<?> defineClass(byte[] data){
return super.defineClass(null,data,0,data.length,null);
}
}
}