AOP和ASM字节码插桩笔记

安卓AOP三剑客:APT,AspectJ,Javassist
细究JVM栈帧&ASM字节码的核心技术
对比图
在这里插入图片描述

Hunter 一个底层基于ASM 和 Gradle Transform API 实现的框架

依赖 https://asm.ow2.io/index.html

implementation  'org.ow2.asm:asm:7.1'
implementation  'org.ow2.asm:asm-commons:7.1'

流程

ClassReader读取字节码->Visitor处理字节码->ClassWriter生成字节码

  1. 准备待插桩Class javac InjectTest.java
  2. javap -v InjectTest.class 反编译得到,关于jvm的操作数栈可以自行了解

以上这两步可以用插件 ASM Bytecode viewer 查看java文件,main方法完整代码生成的字节码是这样的,后面字节码插桩方法照着对应的地方翻译过去就可以了

  public static main([Ljava/lang/String;)V throws java/lang/InterruptedException 
    INVOKESTATIC java/lang/System.currentTimeMillis ()J
    LSTORE 1
    LDC 100
    INVOKESTATIC java/lang/Thread.sleep (J)V
    INVOKESTATIC java/lang/System.currentTimeMillis ()J
    LLOAD 1
    LSUB
    LSTORE 3
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    NEW java/lang/StringBuilder
    DUP
    INVOKESPECIAL java/lang/StringBuilder.<init> ()V
    LDC "time: "
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
    LLOAD 3
    INVOKEVIRTUAL java/lang/StringBuilder.append (J)Ljava/lang/StringBuilder;
    INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
    RETURN
    MAXSTACK = 4
    MAXLOCALS = 5
}
	public class InjectTest {
    public static void main(String[] args) throws InterruptedException {
        //long l=System.currentTimeMillis();
        Thread.sleep(100);
        //long allTime = System.currentTimeMillis() - l;
        //System.out.println("time: "+ allTime);
    }
	}

	public class ASMUnitTest {
    @Test
    public void test() throws IOException {

        //1
        FileInputStream file=new FileInputStream("/Users/fred/AndroidStudioProjects/Test/app/src/test/java/com/example/test/asm/InjectTest.class");

        //2
  		ClassReader classReader = new ClassReader(file);
        ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS);
        classReader.accept(new ClassVisitor(Opcodes.ASM5,classWriter) {
       
            @Override
            public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
                MethodVisitor methodVisitor = super.visitMethod(access, name, descriptor, signature, exceptions);
                MyMethodVistor myMethodVistor = new MyMethodVistor(Opcodes.ASM5, methodVisitor, access, name, descriptor);
                System.out.println("access:" + access + " name:" + name);
                return myMethodVistor;
            }
        },ClassReader.EXPAND_FRAMES);
        //3
        byte[] bytes=classWriter.toByteArray();
        FileOutputStream fos=new FileOutputStream("/Users/fred/AndroidStudioProjects/Test/app/src/test/java/com/example/test/asm/InjectTest.class");
        fos.write(bytes);
        fos.close();
    }
	public class MyMethodVistor extends AdviceAdapter{
        /**
         * Constructs a new {@link AdviceAdapter}.
         *
         * @param api           the ASM API version implemented by this visitor. Must be one of {@link
         *                      Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
         * @param methodVisitor the method visitor to which this adapter delegates calls.
         * @param access        the method's access flags (see {@link Opcodes}).
         * @param name          the method's name.
         * @param descriptor    the method's descriptor (see {@link //Type Type}).
         */
        protected MyMethodVistor(int api, MethodVisitor methodVisitor, int access, String name, String descriptor) {
            super(api, methodVisitor, access, name, descriptor);
        }

        @Override
        protected void onMethodEnter() {
            super.onMethodEnter();
            //方法进入 但是要有方法声明了ASMTest注解的地方才插入
            //long l=System.currentTimeMillis();
            //INVOKESTATIC java/lang/System.currentTimeMillis ()J
    		//LSTORE 1
            invokeStatic(Type.getType("Ljava/lang/System;"),new Method("currentTimeMills","()J"));
            int index = newLocal(Type.LONG_TYPE);
            storeLocal(index,Type.LONG_TYPE);
        }

        @Override
        protected void onMethodExit(int opcode) {
            super.onMethodExit(opcode);
            System.out.println("onMethodExit:"+opcode);
            //这里退出前处理
            //long allTime = System.currentTimeMillis() - l;
        	//System.out.println("time: "+ allTime);
        }

        /*@Override
        public void monitorEnter() {
            super.monitorEnter();
            //同步代码块的进入
        }

        @Override
        public void monitorExit() {
            super.monitorExit();
            //同步代码块的退出
        }*/
    }

在这里插入图片描述

MethodVisitor中的visitAnnotation方法在这里插入图片描述
插件第二个tab可以直接生成字节码数组
在这里插入图片描述
transform gradle插件自动埋点
在这里插入图片描述
获取所有输入的class文件,逐一处理在这里插入图片描述
在这里插入图片描述

请添加图片描述

请添加图片描述
请添加图片描述

请添加图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,关于Spring AOP笔记和源码讲解,我可以给你简单介绍一下。 Spring AOP是Spring框架中的一个重要模块,提供了基于代理的AOP实现。AOP(Aspect Oriented Programming)面向切面编程,是一种编程思想,它通过将横切关注点与业务逻辑分离,使得系统的关注点更加清晰,代码更加简洁易懂,同时也提高了代码的可维护性和可扩展性。 在Spring AOP中,切面(Aspect)是一个类,它包含了通知(Advice)和切点(Pointcut)。通知是在切点上执行的操作,例如在方法执行前或执行后执行一些额外的逻辑。而切点则是一个表达式,用于匹配目标对象中的方法,从而确定哪些方法会被通知所影响。 Spring AOP提供了四种通知类型,分别是: 1. 前置通知(Before advice):在目标方法执行之前执行。 2. 后置通知(After returning advice):在目标方法执行之后执行,在目标方法没有抛出异常的情况下。 3. 异常通知(After throwing advice):在目标方法抛出异常后执行。 4. 最终通知(After advice):无论目标方法是否抛出异常,最终通知都会执行。 除了通知之外,Spring AOP还提供了环绕通知(Around advice),它可以在目标方法执行前和执行后执行一些额外的逻辑,并且可以控制目标方法的执行。 在Spring AOP中,代理是通过JDK动态代理或者CGLIB字节码生成技术生成的。如果目标对象实现了接口,则使用JDK动态代理实现代理;如果目标对象没有实现接口,则使用CGLIB字节码生成技术实现代理。 在Spring AOP中,通知和切点都可以使用注解的方式来声明。例如,使用@Aspect注解声明一个切面类,使用@Before、@After、@AfterReturning、@AfterThrowing和@Around注解声明通知方法,使用@Pointcut注解声明切点表达式。 关于Spring AOP源码讲解,它的实现主要涉及到以下几个类: 1. AdvisedSupport类:封装了目标对象、切面和通知等信息。 2. ProxyFactory类:用于生成代理对象的工厂类。 3. AopProxy接口:代理对象的接口。 4. JdkDynamicAopProxy和CglibAopProxy类:实现了AopProxy接口,分别用于基于JDK动态代理和CGLIB字节码生成技术的代理对象。 以上是Spring AOP笔记和简单源码讲解,希望能对你有所帮助。如果有什么不清楚的地方,可以继续问我。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值