1.目的:实现对函数执行监听,在函数调用前,后得到通知。考虑用asm来实现。
2.资料:在网上看到关于asm的技术资料,写了一个简单的实现。参考链接如下:
http://www.cnblogs.com/eafy/archive/2008/06/18/1224633.html
http://alvinqq.iteye.com/blog/940965
http://www.ibm.com/developerworks/cn/java/j-lo-asm30/
http://ayufox.iteye.com/blog/668917
3.代码:asmAopClassAdapter 该类对目标类进行操作。
asmAopMethodAdapter 对目标类的方法做操作。
ChangeToChildConstructorMethodAdapter该类生成目标类的子类。
asmAopGenerator 一个工具类,生成代理目标类的对象。
asmAopInvoker 函数注入类
测试类
输出结果
4.目的基本达成。
5.待改进,在监听函数执行后,是用的try和catch抛异常的方式来实现。
2.资料:在网上看到关于asm的技术资料,写了一个简单的实现。参考链接如下:
http://www.cnblogs.com/eafy/archive/2008/06/18/1224633.html
http://alvinqq.iteye.com/blog/940965
http://www.ibm.com/developerworks/cn/java/j-lo-asm30/
http://ayufox.iteye.com/blog/668917
3.代码:asmAopClassAdapter 该类对目标类进行操作。
- public class asmAopClassAdapter extends ClassAdapter{
- private String enhancedSuperName,enhancedName;
- private String method;
- private String startInfo,endInfo;
- public asmAopClassAdapter(ClassVisitor cv,String methodName,String start,String end) {
- //Responsechain 的下一个 ClassVisitor,这里我们将传入 ClassWriter,
- // 负责改写后代码的输出
- super(cv);
- method = methodName;
- startInfo = start;
- endInfo = end;
- }
- // 重写 visitMethod,访问到 "method" 方法时,
- // 给出自定义 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) {
- if (name.equals(method)) {
- wrappedMv = new asmAopMethodAdapter(mv,startInfo,endInfo);
- } else if (name.equals("<init>")) {
- wrappedMv = new ChangeToChildConstructorMethodAdapter(mv,
- enhancedSuperName);
- }
- }
- return wrappedMv;
- }
- public void visit(final int version, final int access, final String name,
- final String signature, final String superName,
- final String[] interfaces) {
- enhancedName = name.replace("/", "$")+"$EnhancedByASM"; // 改变类命名
- enhancedSuperName = name; // 改变父类
- super.visit(version, access, enhancedName, signature,
- enhancedSuperName, interfaces);
- }
- public String getEnhancedName() {
- return enhancedName;
- }
- }
asmAopMethodAdapter 对目标类的方法做操作。
- public class asmAopMethodAdapter extends MethodAdapter implements Opcodes{
- private final static int EXCEPTION_STACK = 2 + 1;//max_stack至少需要能够容纳2个常量地址(监控方法使用)和1个exception地址
- private Label try_catch_start,try_catch_end;
- private String startInfo,endInfo;
- public asmAopMethodAdapter(MethodVisitor mv,String start,String end) {
- super(mv);
- try_catch_start = new Label();
- try_catch_end = new Label();
- startInfo = start;
- endInfo = end;
- }
- public void visitCode() {
- mv.visitCode();
- mv.visitLabel(try_catch_start);
- mv.visitLdcInsn(startInfo);
- //asmAopInvoker 这里写类的路径例如:com.asm.asmAopInvoker 应写成 com/asm/asmAopInvoker
- mv.visitMethodInsn(INVOKESTATIC, "asmAopInvoker",
- "methodStart", "(Ljava/lang/String;)V");
- }
- public void visitInsn(int opcode){
- if(opcode >= IRETURN && opcode <= RETURN){
- mv.visitLdcInsn(endInfo);
- //asmAopInvoker 这里写类的路径例如:com.asm.asmAopInvoker 应写成 com/asm/asmAopInvoker
- mv.visitMethodInsn(INVOKESTATIC, "asmAopInvoker",
- "methodEnd", "(Ljava/lang/String;)V");
- }
- mv.visitInsn(opcode);
- }
- public void visitEnd() {
- mv.visitLabel(try_catch_end);
- mv.visitTryCatchBlock(try_catch_start, try_catch_end, try_catch_end, null);
- mv.visitLdcInsn(endInfo);
- //asmAopInvoker 这里写类的路径例如:com.asm.asmAopInvoker 应写成 com/asm/asmAopInvoker
- mv.visitMethodInsn(INVOKESTATIC, "asmAopInvoker",
- "methodEnd", "(Ljava/lang/String;)V");
- mv.visitInsn(Opcodes.ATHROW);
- mv.visitEnd();
- }
- public void visitMaxs(int maxStack,int maxLocals){
- //保证max stack足够大
- mv.visitMaxs(Math.max(EXCEPTION_STACK,maxStack), maxLocals);
- }
- }
ChangeToChildConstructorMethodAdapter该类生成目标类的子类。
- 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
- }
- }
asmAopGenerator 一个工具类,生成代理目标类的对象。
- public class asmAopGenerator {
- private AOPGeneratorClassLoader classLoader ;
- public asmAopGenerator(){
- classLoader = new AOPGeneratorClassLoader();
- }
- public Object proxy(Class c,String methodName,String startInfo,String endInfo) {
- try{
- if( c != null){
- String classPach = c.toString().replace("/", ".");
- ClassReader cr = new ClassReader(classPach.substring(6,classPach.length()));
- ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
- asmAopClassAdapter classAdapter = new asmAopClassAdapter(cw,methodName,startInfo,endInfo);
- cr.accept(classAdapter, ClassReader.SKIP_DEBUG);
- byte[] data = cw.toByteArray();
- Class obj = classLoader.defineClassFromClassFile(classAdapter.getEnhancedName(), data);
- //TODO:隐藏BUG
- return obj.newInstance();
- }}catch(Exception e){
- e.printStackTrace();
- }
- return null;
- }
- class AOPGeneratorClassLoader extends ClassLoader {
- public Class defineClassFromClassFile(String className,
- byte[] classFile) throws ClassFormatError {
- return defineClass(className, classFile, 0,
- classFile.length);
- }
- }
- }
asmAopInvoker 函数注入类
- public class asmAopInvoker {
- public static void methodEnd(String evtID){
- System.out.println(evtID);
- }
- public static void methodStart(String evtID){
- System.out.println(evtID);
- }
- }
测试类
- public class helloWorld {
- public void sayHello(){
- System.out.println("helloWorld....");
- }
- public static void main(String[]args){
- asmAopGenerator aag = new asmAopGenerator();
- helloWorld hw = (helloWorld) aag.proxy(helloWorld.class, "sayHello", "it's begin", "it's end");
- hw.sayHello();
- }
- }
输出结果
- it's begin
- helloWorld....
- it's end
4.目的基本达成。
5.待改进,在监听函数执行后,是用的try和catch抛异常的方式来实现。
6.环境 asm 3.3.1 jdk 1.6.