JAVA AOP之ASM

这是ASM的定义:

ASM 是一个 Java 字节码操控框架。它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。

ASM的核心原理是,通过读取.class文件并动态修改文件的属性、方法、范围权限等,来替换或生成新的类并加载到运行环境中。

        相对于动态代理来说,动态代理的对象必须实现接口,切入的方法必须是接口中的定义的方法,而对于ASM来说就没有这个限制,普通的JAVA类的任何方法都可以切入代码了。动态代理使用了一定的反射,在性能上比ASM要差一些。

原始类Account,要求在operation之前进行安全检查,在operation执行之后记录日志:

/**
 * @author Administrator
 * 测试账号类
 */
public class Account { 
	protected String name;
	
	public void operation() 
	{ 
		 System.out.println("operation..."+name); 
	} 
}
进行安全检查和日志记录的类在SecurityChecker中定义,checkSecurity和log方法模拟权限检查和日志记录:

public class SecurityChecker {

	public static void checkSecurity(){
		System.out.println("checkSecurity.......");
	}
	public static void log(){
		System.out.println("log.......");
	}
}
使用ASM对原始类进行改造,首先将新类继承于原始类 Account,定义子类构造方法Adapter
public class ChangeToChildConstructorMethodAdapter extends MethodAdapter {

	private String superClassName; 
	
	public ChangeToChildConstructorMethodAdapter(MethodVisitor arg0,String superClassName) {
		super(arg0);
		this.superClassName = superClassName; 
	}
	
	public void visitMethodInsn(int opcode, String owner, String name, 
			 String desc) { 
			 // 调用父类的构造函数时
			 if (opcode == Opcodes.INVOKESPECIAL && name.equals("<init>")) { 
				 owner = superClassName; 
			 } 
			 super.visitMethodInsn(opcode, owner, name, desc);// 改写父类为 superClassName 
		 } 
}

改造operation方法,定义方法Adapter:

public class AddCheckMethodAdapter extends MethodAdapter {

	public AddCheckMethodAdapter(MethodVisitor arg0) {
		super(arg0);
	}
	//方法开始前插入代码:权限控制
	public void visitCode() { 
		 visitMethodInsn(Opcodes.INVOKESTATIC, "com/zone/asm/SecurityChecker", 
			"checkSecurity", "()V"); 
	} 
	//方法返回之前插入代码:日志检查
	public void visitInsn(int opcode) {
        if (opcode == Opcodes.RETURN) {//在返回之前安插after 代码。
            visitMethodInsn(Opcodes.INVOKESTATIC, "com/zone/asm/SecurityChecker", "log", "()V");
        }
        super.visitInsn(opcode);
    }
}

定义工厂类生产新的子类

public class SecureAccountGenerator {
	private static AccountGeneratorClassLoader classLoader = 
	        new AccountGeneratorClassLoader(); 
	    
    private static Class secureAccountClass; 
    
    public static Account generateSecureAccount() throws ClassFormatError, 
        InstantiationException, IllegalAccessException,IOException,ClassNotFoundException { 
        //生成子类
    	if (null == secureAccountClass) {            
            ClassReader cr = new ClassReader("com.zone.asm.Account"); 
            ClassWriter cw = new ClassWriter(true); 
            ClassAdapter classAdapter = new AddSubClassClassAdapter(cw);
            cr.accept(classAdapter, true); 
            byte[] data = cw.toByteArray(); 
            //这里讲子类写到磁盘中,可选
            File file = new File("F:/Account$EnhancedByASM.class"); 
   		 	FileOutputStream fout = new FileOutputStream(file); 
   		 	fout.write(data); 
   		 	fout.close();
   		 	//由字节码定义类
            secureAccountClass = classLoader.defineClassFromClassFile( 
               "com.zone.asm.Account$EnhancedByASM",data); 
        } 
        //生成实例
        return (Account) secureAccountClass.newInstance(); 
    } 
    //自定义classLoader
    private static class AccountGeneratorClassLoader extends ClassLoader {
    	
        public Class defineClassFromClassFile(String className, 
            byte[] classFile) throws ClassFormatError { 
            return defineClass(className, classFile, 0, classFile.length);
        } 
    } 
    public static void main(String [] args) throws Exception{
    	Account a = SecureAccountGenerator.generateSecureAccount();
    	a.name = "zhl";
    	a.operation();
    	
    	System.out.println(Account.class.getClassLoader());
    	System.out.println(a.getClass().getClassLoader());
    	
    	//引导classLoader加载的JAR
    	URL[] urls=sun.misc.Launcher.getBootstrapClassPath().getURLs();
        for (int i = 0; i < urls.length; i++) {
          System.out.println(urls[i].toExternalForm());
        }
        
        System.out.println(System.getProperty("java.ext.dirs"));
        ClassLoader extensionClassloader=ClassLoader.getSystemClassLoader().getParent();
        System.out.println("the parent of extension classloader : "+extensionClassloader.getParent());
        
    }

使用JD-GUI工具打开新生成的子类,可以看到operate方法里增加了安全检查和日志记录的代码:
public class EnhancedByASM extends Account
{
  protected String name;

  public void operation()
  {
    SecurityChecker.checkSecurity();
    System.out.println("operation..." + this.name);
    SecurityChecker.log();
  }
}





  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值