ASM 是一个 Java 字节码操控框架。它能够以二进制形式修改已有类或者动态生成类。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。ASM 从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。
示例中演示的功能:
生成被代理类的子类,并重写所有方法(除java.lang.Object类定义的方法),增加before和after拦截。
重新定义被代理类的所有属性(不包括属性的赋值)。
把生成的class文件保存到硬盘中。
从内存中加载新生成的class。
package org.cc.demo2;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
/**
*
* <p>根据class A生成一个class B extends A</p>
* <li>重写A及A父类的所有方法,eg. public void xx() {super.xx();}
* <li>copy A类定义的所有属性
*
* @author dixingxing
* @date May 3, 2012
*/
public class ClassAdapter extends ClassVisitor implements Opcodes{
public static final String INIT = "<init>";
private ClassWriter classWriter;
private String originalClassName;
private String enhancedClassName;
private Class<?> originalClass;
public ClassAdapter(String enhancedClassName,
Class<?> targetClass, ClassWriter writer) {
super(Opcodes.ASM4,writer);
this.classWriter = writer;
this.originalClassName = targetClass.getName();
this.enhancedClassName = enhancedClassName;
this.originalClass = targetClass;
}
@Override
public void visit(int version, int access, String name, String signature,
String superName, String[] interfaces) {
cv.visit(version, Opcodes.ACC_PUBLIC,
toAsmCls(enhancedClassName), signature, name,
interfaces);
}
@Override
public FieldVisitor visitField(int access, String name, String desc,
String signature, Object value) {
// 拷贝所有属性 可使用java反射给属性赋值(生成class后newInstance在赋值)
return super.visitField(access, name, desc, signature, value);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc,
String signature, String[] exceptions) {
// 删除所有方法
return null;
}
/**
* 把类名中的.替换为/
* @param className
* @return
*/
private static String toAsmCls(String className) {
return className.replace('.', '/');
}
/**
*
* <p>前置方法</p>
*
* @see TxHandler
* @param mWriter
*/
private static void doBefore(MethodVisitor mWriter,String methodInfo) {
mWriter.visitFieldInsn(GETSTATIC,"java/lang/System","out","Ljava/io/PrintStream;");
mWriter.visitLdcInsn("before method : " + methodInfo);
mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println",
"(Ljava/lang/String;)V");
// 或者直接调用静态方法
// mWriter.visitLdcInsn(methodInfo);
// mWriter.visitMethodInsn(INVOKESTATIC,toAsmCls(TxHandler.class.getName()),"before","(Ljava/lang/String;)V");
}
/**
*
* <p>后置方法</p>
* @see TxHandler
* @param mWriter
*/
private static void doAfter(MethodVisitor mWriter,String methodInfo) {
mWriter.visitFieldInsn(GETSTATIC,"java/lang/System","out","Ljava/io/PrintStream;");
mWriter.visitLdcInsn("after method : " + methodInfo);
mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println",
"(Ljava/lang/String;)V");
}
/**
*
* <p>
* object类本身的方法不做重写
* </p>
* <p>
* "main" 方法不做重写
* </p>
*
* @param m
* @return
*/
public static boolean needOverride(Method m) {
// object类本身的方法不做重写
if (m.getDeclaringClass().getName().equals(Object.class.getName())) {
return false;
}
// "main" 方法不做重写
if (Modifier.isPublic(m.getModifiers())
&& Modifier.isStatic(m.getModifiers())
&& m.getReturnType().getName().equals("void")
&& m.getName().equals("main")) {
return false;
}
return true;
}
@Override
public void visitEnd() {
// 如果originalClass定义了私有成员变量,那么直接在visitMethod中复制originalClass的<init>会报错。
// ALOAD 0
// INVOKESPECIAL cc/RoleService.<init>()V
// RETURN
// // 调用originalClassName的<init>方法,否则class不能实例化
MethodVisitor mvInit = classWriter.visitMethod(ACC_PUBLIC, INIT, "()V", null, null);
mvInit.visitVarInsn(ALOAD, 0);
mvInit.visitMethodInsn(INVOKESPECIAL, toAsmCls(originalClassName), INIT, "()V");
mvInit.visitInsn(RETURN);
mvInit.visitMaxs(0, 0);
mvInit.visitEnd();
// 获取所有方法,并重写(main方法 和 Object的方法除外)
Method[] methods = originalClass.getMethods();
for(Method m : methods) {
if(!needOverride(m)) {
continue;
}
Type mt = Type.getType(m);
StringBuilder methodInfo = new StringBuilder(originalClassName);
methodInfo.append(".").append(m.getName());
methodInfo.append("|");
Class<?>[] paramTypes = m.getParameterTypes();
for(Class<?> t : paramTypes) {
methodInfo.append(t.getName()).append(",");
}
if(paramTypes.length > 0) {
methodInfo.deleteCharAt(methodInfo.length() - 1);
}
// 方法是被哪个类定义的
String declaringCls = toAsmCls(m.getDeclaringClass().getName());
// 方法 description
MethodVisitor mWriter = classWriter.visitMethod(ACC_PUBLIC, m.getName(), mt.toString(), null, null);
// insert code here (before)
doBefore(mWriter,methodInfo.toString());
int i = 0;
// 如果不是静态方法 load this对象
if(!Modifier.isStatic(m.getModifiers())) {
mWriter.visitVarInsn(ALOAD, i++);
}
StringBuilder sb = new StringBuilder(m.getName());
// load 出方法的所有参数
for(Class<?> tCls : m.getParameterTypes()) {
Type t = Type.getType(tCls);
sb.append(loadCode(t)).append(",");
mWriter.visitVarInsn(loadCode(t), i++);
if(t.getSort() == Type.LONG || t.getSort() == Type.DOUBLE) {
i++;
}
}
// super.xxx();
mWriter.visitMethodInsn(INVOKESPECIAL,declaringCls,m.getName(),mt.toString());
// 处理返回值类型
Type rt = Type.getReturnType(m);
// 没有返回值
if(rt.toString().equals("V")) {
doAfter(mWriter,methodInfo.toString());
mWriter.visitInsn(RETURN);
}
// 把return xxx() 转变成 : Object o = xxx(); return o;
else {
int storeCode = storeCode(rt);
int loadCode = loadCode(rt);
int returnCode = rtCode(rt);
mWriter.visitVarInsn(storeCode, i);
doAfter(mWriter,methodInfo.toString());
mWriter.visitVarInsn(loadCode, i);
mWriter.visitInsn(returnCode);
}
// 已设置了自动计算,但还是要调用一下,不然会报错
mWriter.visitMaxs(i, ++i);
mWriter.visitEnd();
}
cv.visitEnd();
}
/**
*
* <p>get StoreCode(Opcodes#xStore)</p>
*
*
* @param type
* @return
*/
public static int storeCode(Type type) {
int sort = type.getSort();
switch (sort) {
case Type.ARRAY:
sort = ASTORE;
break;
case Type.BOOLEAN:
sort = ISTORE;
break;
case Type.BYTE:
sort = ISTORE;
break;
case Type.CHAR:
sort = ISTORE;
break;
case Type.DOUBLE:
sort = DSTORE;
break;
case Type.FLOAT:
sort = FSTORE;
break;
case Type.INT:
sort = ISTORE;
break;
case Type.LONG:
sort = LSTORE;
break;
case Type.OBJECT:
sort = ASTORE;
break;
case Type.SHORT:
sort = ISTORE;
break;
default:
break;
}
return sort;
}
/**
*
* <p>get StoreCode(Opcodes#xLOAD)</p>
*
* @param type
* @return
*/
public static int loadCode(Type type) {
int sort = type.getSort();
switch (sort) {
case Type.ARRAY:
sort = ALOAD;
break;
case Type.BOOLEAN:
sort = ILOAD;
break;
case Type.BYTE:
sort = ILOAD;
break;
case Type.CHAR:
sort = ILOAD;
break;
case Type.DOUBLE:
sort = DLOAD;
break;
case Type.FLOAT:
sort = FLOAD;
break;
case Type.INT:
sort = ILOAD;
break;
case Type.LONG:
sort = LLOAD;
break;
case Type.OBJECT:
sort = ALOAD;
break;
case Type.SHORT:
sort = ILOAD;
break;
default:
break;
}
return sort;
}
/**
*
* <p>get StoreCode(Opcodes#xRETURN)</p>
*
* @param type
* @return
*/
public static int rtCode(Type type) {
int sort = type.getSort();
switch (sort) {
case Type.ARRAY:
sort = ARETURN;
break;
case Type.BOOLEAN:
sort = IRETURN;
break;
case Type.BYTE:
sort = IRETURN;
break;
case Type.CHAR:
sort = IRETURN;
break;
case Type.DOUBLE:
sort = DRETURN;
break;
case Type.FLOAT:
sort = FRETURN;
break;
case Type.INT:
sort = IRETURN;
break;
case Type.LONG:
sort = LRETURN;
break;
case Type.OBJECT:
sort = ARETURN;
break;
case Type.SHORT:
sort = IRETURN;
break;
default:
break;
}
return sort;
}
}
