• 欢迎访问开心洋葱网站,在线教程,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站,欢迎加入开心洋葱 QQ群
  • 为方便开心洋葱网用户,开心洋葱官网已经开启复制功能!
  • 欢迎访问开心洋葱网站,手机也能访问哦~欢迎加入开心洋葱多维思维学习平台 QQ群
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏开心洋葱吧~~~~~~~~~~~~~!
  • 由于近期流量激增,小站的ECS没能经的起亲们的访问,本站依然没有盈利,如果各位看如果觉着文字不错,还请看官给小站打个赏~~~~~~~~~~~~~!

asm 动态代理的例子

OC/C/C++ 水墨上仙 2665次浏览

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;
	}
}


开心洋葱 , 版权所有丨如未注明 , 均为原创丨未经授权请勿修改 , 转载请注明asm 动态代理的例子
喜欢 (0)
加载中……