论坛首页 Java企业应用论坛

AOP:ASM直接为类方法添加前拦截执行--无损方法

浏览 4035 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2012-03-11  

//所谓无损即 在不改变原有类文件的情况下,为指定方法 添加前拦截,总体实现与前一个例子差不多,但是不需要生产新的类文件。

//思路:
//改变 Class Description, 将其命名为 Account$EnhancedByASM,将其父类指定为 AccountASM。
//改变构造函数,将其中对父类构造函数的调用转换为对 AccountASM构造函数的调用。

//著名的 Hibernate 和 Spring 框架,就是使用这种技术实现了 AOP 的“无损注入”。

//1、首先实现一个 实现一个 methodAdapter 类,用于 修改方法,已经存在AddSecurityCheckMethodAdapter  上例子

//2、再实现一个methodAdapter 类,用于构建新类Account$EnhancedByASM,将其父类指定为 AccountASM

package com.aop;

import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

public class ChangeToChildConstructorMethodAdapter extends MethodAdapter {
 private String superClassName;

  public ChangeToChildConstructorMethodAdapter(MethodVisitor mv,
   String superClassName) {
   super(mv);
   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
  }

}

//3、完善AddSecurityCheckClassAdapter 类,控制生产新的类和修改类方法

public class AddSecurityCheckClassAdapter extends ClassAdapter
{

 public String enhancedSuperName;
 public AddSecurityCheckClassAdapter(ClassVisitor cv) {
        //Responsechain 的下一个 ClassVisitor,这里我们将传入 ClassWriter,
        // 负责改写后代码的输出
        super(cv);
    }


 public void visit(final int version, final int access, final String name,
    final String signature, final String superName,
    final String[] interfaces) {
   String enhancedName = name + "$EnhancedByASM";  // 改变类命名
   enhancedSuperName = name; // 改变父类,这里是”Account”
   super.visit(version, access, enhancedName, signature,
   enhancedSuperName, interfaces);
  }


    // 重写 visitMethod,访问到 "operation" 方法时,
    // 给出自定义 MethodVisitor,实际改写方法内容
    public MethodVisitor visitMethod(final int access, final String name,
        final String desc, final String signature, final String[] exceptions) {
        MethodVisitor mv = cv.visitMethod(access, name, desc, signature,exceptions);
        MethodVisitor wrappedMv = mv;
        if (mv != null) {
            // 对于 "operation" 方法
            if (name.equals("operation")) {
                // 使用自定义 MethodVisitor,实际改写方法内容
                wrappedMv = new AddSecurityCheckMethodAdapter(mv);
            }
            else if (name.equals("<init>")) {
       wrappedMv = new ChangeToChildConstructorMethodAdapter(mv,
         enhancedSuperName);
       }

        }
        return wrappedMv;
    }

}

//4、新建Generator类,用户获取新生产的类对象

public class Generator {


 private static AccountGeneratorClassLoader classLoader =
        new AccountGeneratorClassLoader();

    private static Class secureAccountClass;

    public static AccountAsm generateSecureAccount() throws Exception {
        if (null == secureAccountClass) {
          ClassReader cr =  new ClassReader("com.aop.AccountAsm");
       ClassWriter cw = new ClassWriter(true);
       ClassAdapter classAdapter = new AddSecurityCheckClassAdapter(cw);
       cr.accept(classAdapter, true);
            byte[] data = cw.toByteArray();
            secureAccountClass = classLoader.defineClassFromClassFile(
               "com.aop.AccountAsm$EnhancedByASM",data);
        }
        return (AccountAsm) secureAccountClass.newInstance();
    }

    private static class AccountGeneratorClassLoader extends ClassLoader {
        public Class defineClassFromClassFile(String className,
            byte[] classFile) throws ClassFormatError {
            return defineClass(className, classFile, 0,
         classFile.length);
        }
    }
}

//5、调用
AccountAsm a=  Generator.generateSecureAccount();
a.operation();

   发表时间:2012-03-12  
aop  分动态织入 静态织入。

楼主所说应该是 动态的植入,就是通过代理实现的。 
静态植入是指 class文件都被改 了。如:apsectj
0 请登录后投票
   发表时间:2012-03-13  
个人建议使用aspectj更加直观
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics