`

使用ASM动态生成类的拦截代理类

阅读更多

文章源自http://www.iteye.com/topic/1123350

 

使用ASM实现AOP功能,根据现有的CLASS类文件,动态生成它的代理类文件,并在所有的方法前后添加拦截处理,具体如下:

1.生成被代理类的子类,并重写所有方法(除java.lang.Object类定义的方法和main),增加before和after拦截。

2.重新定义被代理类的所有属性(不包括属性的赋值及父类属性)。

jdk自带的代理(InvocationHandler)的不足:

1.jdk只能代理接口(被代理的类必须实现至少一个接口)。

2.jdk提供的代理方法,不能拦截同一类中方法的调用。如A.method1(){this.method2();}

此时method2将不会被拦截。

下面是简单的被代理类及父类(也可以不要父类):

public class Service{
	public String name;
	public void insert(Object o) {}
}
public class RoleService extends Service{
	public String roleName;
	public String executeOuter(Integer name) {
		System.out.println("executeOuter call super.query()");
		return query();
	}
	public String query() {
		System.out.println("execute (RoleService): query");
		return "query result (RoleService)";
	}
}

 核心类ClassAdapter用于生成一个类的子类,并为所有代理类方法添加拦截方法,如下:

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

	private static String toAsmCls(String className) {
		return className.replace('.', '/');
	}
	
	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");

	}
	
	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");  
	}
	
	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>会报错。
		// 创建<init>并调用父类的<init>
		// 调用originalClassName的<init>方法,否则class不能实例化
		MethodVisitor mvInit = classWriter.visitMethod(ACC_PUBLIC, INIT, "()V", null, null); 
		// pushes the 'this' variable
		mvInit.visitVarInsn(ALOAD, 0);
		mvInit.visitMethodInsn(INVOKESPECIAL, toAsmCls(originalClassName), INIT, "()V");
		mvInit.visitInsn(RETURN);
		// this code uses a maximum of one stack element and one local variable
		mvInit.visitMaxs(0, 0);
		mvInit.visitEnd(); 
		
		// 获取所有方法,并重写(main方法 和 Object的方法除外)
		Method[] methods = originalClass.getMethods();
		for(Method m : methods) {
			if(!needOverride(m)) {
				continue;
			}
			// mt.toString() == ()Ljava/lang/String
			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);
			}
			
			// 方法 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++); 
				// long和double 用64位表示,要后移一个位置,否则会报错
				if(t.getSort() == Type.LONG || t.getSort() == Type.DOUBLE) {
					i++;
				}
			}
			
			// 方法所属类全名
			String declaringCls = toAsmCls(m.getDeclaringClass().getName());
			// 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;
			// store/load 存储并载入变量
			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();
	}
	
	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;
	}
	
	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;
	}
	
	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;
	}
}

 具体调用类如下:

public class AsmFactory {
	public static final String SUFIX = "$EnhancedByCc";
	public static BytecodeLoader classLoader = new BytecodeLoader();

	/**
	 * 根据字节码加载class
	 */
	public static class BytecodeLoader extends ClassLoader {
		public Class<?> defineClass(String className, byte[] byteCodes) {
			return super.defineClass(className, byteCodes, 0, byteCodes.length);
		}
	}

	/**
	 * 返回代理类
	 */
	@SuppressWarnings("unchecked")
	protected static <T> Class<T> getEnhancedClass(Class<T> clazz){
		String enhancedClassName = clazz.getName() + SUFIX;
		try {
			return (Class<T>) classLoader.loadClass(enhancedClassName);
		} catch (ClassNotFoundException classNotFoundException) {
			ClassReader reader = null;
			try {
				reader = new ClassReader(clazz.getName());
			} catch (IOException ioexception) {
				throw new RuntimeException(ioexception);
			}
			ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
			ClassVisitor visitor = new ClassAdapter(enhancedClassName, clazz,
					writer);
			reader.accept(visitor, 0);
			byte[] byteCodes = writer.toByteArray();
			writeClazz(enhancedClassName, byteCodes);
			Class<T> result = (Class<T>) classLoader.defineClass(
					enhancedClassName, byteCodes);
			return result;
		}
	}
	
	public static void writeClazz(String name, byte[] data) {
		try {
			File file = new File("D:/com/" + name + ".class");
			FileOutputStream fout = new FileOutputStream(file);

			fout.write(data);
			fout.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) throws InstantiationException, IllegalAccessException {
		Class<RoleService> rsCls = getEnhancedClass(RoleService.class);
		rsCls.newInstance().executeOuter(1);
	}
}

 使用反编译工具查看生成的字节码,如下:

public class RoleService$EnhancedByCc extends RoleService
{
  public String roleName;

  public String query()
  {
    System.out.println("before method : org.cc.demo2.RoleService.query|");
    String str = super.query();
    System.out.println("after method : org.cc.demo2.RoleService.query|");
    return str;
  }

  public String executeOuter(Integer paramInteger)
  {
    System.out.println("before method : org.cc.demo2.RoleService.executeOuter|java.lang.Integer,");
    String str = super.executeOuter(paramInteger);
    System.out.println("after method : org.cc.demo2.RoleService.executeOuter|java.lang.Integer,");
    return str;
  }

  public void insert(Object paramObject)
  {
    System.out.println("before method : org.cc.demo2.RoleService.insert|java.lang.Object,");
    super.insert(paramObject);
    System.out.println("after method : org.cc.demo2.RoleService.insert|java.lang.Object,");
  }
}

 

 

分享到:
评论
发表评论

文章已被作者锁定,不允许评论。

相关推荐

    ASM操作字节码,动态生成Java类class文件

    当使用CGLIB时,Spring实际上就是在底层利用ASM来生成代理类的字节码。 在ASM中,我们首先需要了解几个核心概念: 1. **ClassWriter**: 这个类负责生成字节码,它是ASM的核心组件之一。通过向ClassWriter发送指令...

    CGLIB 和 JDK生成动态代理类的区别

    它使用ASM库在内存中构建新的字节码,生成的目标类会继承自原始类。因此,对于没有实现接口的类,CGLIB可以提供动态代理功能。 性能方面,CGLIB通常比JDK动态代理更快,因为它是基于字节码生成的子类,而JDK动态...

    cglib和asm

    5. 数据持久化:ORM框架如Hibernate利用CGlib和ASM来生成代理类,实现对象到数据库的映射。 总的来说,CGlib和ASM是Java开发中的重要工具,它们通过字节码操作提供了一种强大的方式来扩展和修改Java程序,使得...

    cglib,字节码生成库是生成和转换Java字节码的高级API。它被aop、测试、数据访问框架用来生成动态代理对象和拦截字段访问。.zip

    当对数据库的访问涉及到复杂的业务规则时,CGlib生成的代理类可以帮助我们实现这些规则,而不必直接修改数据访问层的代码。 **开源项目** CGlib作为一个开源项目,具有以下优势: 1. **社区支持**:由于其开源...

    ASM函数监听实现(三)拦截注入函数的参数值 (函数执行前)

    ASM库是一个轻量级的Java字节码操控和分析框架,常用于动态代理、代码生成以及AOP实现。本篇文章将深入探讨如何使用ASM库来实现函数监听,特别是如何在函数执行前拦截并改变其参数值。 首先,我们需要理解ASM库的...

    cglib动态生成java类

    // 设置被代理类 enhancer.setSuperclass(MyClass.class); // 设置回调函数 enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, ...

    Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM)

    Java动态代理机制是一种在运行时创建代理类和对象的技术,它可以让我们在不修改原有代码的情况下,为已有接口或类添加额外的功能。动态代理通常用于实现AOP(面向切面编程)、事件监听、缓存处理、日志记录等功能。...

    java代理机制 JDK动态代理和cglib代理 详解

    CGLIB使用ASM库在运行时动态生成字节码,创建目标类的子类,从而实现对目标类方法的增强。 1. **Enhancer类** - `Enhancer`是CGLIB的主要入口,它扮演了工厂的角色,通过它可以配置代理对象的行为,并生成代理子类...

    cglib-2.2.jar asm-tree.jar asm-commons.jar asm.jar

    【描述】"cglib动态代理模式jar包 cglib-2.2.jar asm-tree.jar asm-commons.jar asm.jar" 指出,这些jar文件是CGlib库的一部分,它是一个强大的、高性能的代码生成库,广泛用于创建Java动态代理和增强现有类。...

    cglib_2.2.2 动态代理jar包(包含asm_3.3.1)

    - CGLIB通过ASM库动态生成一个目标类的子类,并重写其方法。当调用被代理对象的方法时,实际上是调用了这个子类的方法。 - 在生成的子类中,CGLIB会添加一个`MethodInterceptor`接口的实现,这个接口定义了`...

    asm-all&&cglib

    1. **动态代理**:生成动态代理类,用于实现接口或者扩展已有类的功能。 2. **代码优化**:在运行时对字节码进行优化,提高程序性能。 3. **AOP(面向切面编程)**:如Spring AOP的实现就利用了ASM来生成代理类。 4....

    org.springframework.asm-3.0.5.RELEASE.jar

    1. 动态代理:Spring AOP利用ASM生成代理类,实现对目标对象的方法拦截。当一个类需要被代理时,Spring会使用ASM生成一个该类的子类,然后在这个子类中加入拦截逻辑,这样就实现了方法的动态代理。 2. CGLIB(Code ...

    cglib.jar | asm.jar对应版本

    在cglib中,asm库用于动态生成字节码,帮助我们创建目标类的子类。ASM提供了一套API,可以直接操作字节码,实现对类的增强,如添加新的方法、字段,或者修改已有方法的行为。 在使用cglib时,通常需要同时引入这两...

    asm + cglib demo

    1. **动态代理**: 创建动态代理类,用于模拟接口的实现,比如在不修改源代码的情况下增强或拦截方法调用。 2. **代码分析**: 分析已存在的类和方法,用于性能优化、代码理解和调试。 3. **代码生成**: 动态生成新的...

    cglib.jar和cglib代理必备的asm所有jar

    Cglib通过继承被代理类的方式生成子类,并在子类中拦截父类方法的调用,从而实现代理功能。 Cglib的使用步骤大致如下: 1. 创建 Enhancer 对象,它是Cglib的核心类,用于设置目标对象和回调函数。 2. 使用Enhancer....

    cglib-3.3.0.jar,asm-7.0.jar

    CGLIB之所以依赖ASM,是因为CGLIB在生成代理类的字节码时,需要ASM提供的低级别API来解析和操作Java字节码。ASM的高效性能和灵活性使得CGLIB能够轻松地生成和优化代理类。 总结来说,"cglib-3.3.0.jar"和"asm-7.0....

    CGlib动态代理类的jar包

    在Java编程中,动态代理是一种在运行时创建代理类和对象的技术,可以用于拦截方法调用,实现AOP(面向切面编程)或者为已有接口或类提供额外功能。CGlib是Java动态代理的一种实现方式,它不是依赖于Java的反射机制,...

    asm-3.3.1.jar

    - **AOP代理**:Spring AOP使用动态代理技术,如JDK动态代理或CGLIB,而CGLIB底层就是基于ASM来生成字节码,创建代理对象。 - **元数据解析**:Spring的依赖注入和自动配置需要解析类的元数据,ASM可以高效地完成这...

    Cglib和asm的jar包

    2. **动态代理**:当目标类没有实现接口时,Cglib可以生成一个目标类的子类作为代理,实现对目标类的方法拦截。 3. **性能优化**:在一些需要高性能的代码生成场景,如ORM框架Hibernate中,Cglib用于生成实体对象的...

    asm的jar包

    - **动态代理**:创建运行时的代理类,拦截并增强方法调用。 - **AOP**:实现切面编程,插入额外的行为,如日志记录、事务管理。 - **代码分析**:分析已有的Java类,获取类结构、方法信息等。 - **代码转换**:修改...

Global site tag (gtag.js) - Google Analytics