天天看点

JAVA通过ASM字节码为成员方法前后添加其他代码1. 代码实例2. 运行结果

1. 代码实例

package asm.demo2.modify.add;

import asm.demo2.create.bean.MyClassLoader;
import org.apache.commons.lang3.StringUtils;
import org.objectweb.asm.*;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import static org.objectweb.asm.Opcodes.*;

/**
 * 为方法的前后添加一些内容
 * @date 2018/12/28 23:28
 */

public class MethodAddCode {

    public static class AddCodeVisitor extends ClassVisitor {

        public AddCodeVisitor(int i, ClassVisitor classVisitor) {
            super(i, classVisitor);
        }

        /**
         * 访问到方法时被调用
         * @param access
         * @param name
         * @param descriptor
         * @param signature
         * @param exceptions
         * @return
         */
        @Override
        public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
            //不代理构造函数
            if(!StringUtils.equals("<init>",name)) {
                MethodVisitor mv = cv.visitMethod(access, name, descriptor, signature, exceptions);
                //方式一
                return new AddCodeMethodVisitor_1(this.api,mv);

                //方式二
               // return new AddCodeMethodVisitor_2(this.api,mv);

            }
            return super.visitMethod(access, name, descriptor, signature, exceptions);
        }
    }

    /**
     * 方式一:通过字节编写字节码的方式织入代码
     */
    public static class AddCodeMethodVisitor_1 extends MethodVisitor {

        public AddCodeMethodVisitor_1(int api, MethodVisitor methodVisitor) {
            super(api, methodVisitor);
        }

        /**方法的开始,即刚进入方法里面*/
        @Override
        public void visitCode() {
            mv.visitFieldInsn(Opcodes.GETSTATIC,"java/lang/System","out","Ljava/io/PrintStream;");
            mv.visitLdcInsn("方式一:方法开始运行");
            mv.visitMethodInsn(INVOKEVIRTUAL,"java/io/PrintStream","println","(Ljava/lang/String;)V");
            super.visitCode();
        }

        @Override
        public void visitInsn(int opcode) {
            if(opcode == ARETURN || opcode == RETURN ) {
                mv.visitFieldInsn(Opcodes.GETSTATIC,"java/lang/System","out","Ljava/io/PrintStream;");
                mv.visitLdcInsn("方式一:方法调用结束");
                mv.visitMethodInsn(INVOKEVIRTUAL,"java/io/PrintStream","println","(Ljava/lang/String;)V");
            }
            super.visitInsn(opcode);
        }

        @Override
        public void visitEnd() {
            mv.visitMaxs(6,6);
            super.visitEnd();
        }
    }

    /**
     * 方式二:通过调用现有的class文件
     */
    public static class AddCodeMethodVisitor_2 extends MethodVisitor {

        public AddCodeMethodVisitor_2(int api, MethodVisitor methodVisitor) {
            super(api, methodVisitor);
        }


        /**方法的开始,即刚进入方法里面*/
        @Override
        public void visitCode() {
            mv.visitMethodInsn(INVOKESTATIC,Log.class.getName().replace(".","/"),"beforeMethod","()V",false);
            super.visitCode();
        }

        @Override
        public void visitInsn(int opcode) {
            if(opcode == ARETURN || opcode == RETURN ) {
                mv.visitMethodInsn(INVOKESTATIC,Log.class.getName().replace(".","/"),"afterMethod","()V",false);
            }
            super.visitInsn(opcode);
        }

        @Override
        public void visitEnd() {
            mv.visitMaxs(6,6);
            super.visitEnd();
        }
    }

    public static void main(String[] args) throws IOException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        String fullName = Demo.class.getName();
        String fullNameType = fullName.replace(".", "/");
        ClassReader cr = new ClassReader(fullNameType);
        ClassWriter cw = new ClassWriter(0);
        AddCodeVisitor cv = new AddCodeVisitor(ASM6,cw);
        cr.accept(cv,ClassReader.SKIP_DEBUG);
        byte[] bytes = cw.toByteArray();

        MyClassLoader classLoader = new MyClassLoader();
        Class<?> cls = classLoader.defineClassPublic(fullName, bytes, 0, bytes.length);

        Object o = cls.newInstance();
        Method getDemoInfo = cls.getMethod("getDemoInfo");
        getDemoInfo.invoke(o);
    }
}

           
package asm.demo2.modify.add;
/**
 * @date 2018/12/28 23:36
 */
public class Demo {
    public void getDemoInfo() {
        System.out.println("getDemoInfo被调用...");
    }
}
           
package asm.demo2.modify.add;

/**
 * 日志代码
 * @date 2018/12/28 23:55
 */
public class Log {

    public static final void beforeMethod() {
        System.out.println("方式二:方法开始运行...");
    }

    public static final void afterMethod() {
        System.out.println("方式二:方法运行结束...");
    }
}
           

2. 运行结果

JAVA通过ASM字节码为成员方法前后添加其他代码1. 代码实例2. 运行结果
JAVA通过ASM字节码为成员方法前后添加其他代码1. 代码实例2. 运行结果