使用ASM字节码框架实现AOP功能

目前实现AOP最常见,最简单的方法就是Propxy模式,写一个代理类,代理类里面持有真实类的引用。
这种方式实现的AOP,多了一层包装
使用ASM的话,就不需要多一层包装了,它是直接把代码植入到class文件里面(严格上说是字节码中)

相当于在代码里面写AOP,因此要想实现 Aop 的关键是,如何将我们的代码安插到被调用方法的相应位置。


首先加入asm的依赖

<dependency>
	<groupId>org.ow2.asm</groupId>
	<artifactId>asm-all</artifactId>
	<version>5.1</version>
</dependency>

package com.agent.my5;

public class Operation
{
	public void oper()
	{
		System.out.println("***********这里是执行的逻辑**********");
	}
}

现在需要对这个类的oper方法做aop,在方法执行之前执行如下类的startLog()方法,方法执行结束后,执行endLog()方法

package com.agent.my5;

public class Log
{
	public static void startLog()
	{
		System.out.println("start log ...");
	}
	
	public static void endLog()
	{
		System.out.println("end log ...");
	}
}

示例代码如下:

package com.agent.my5;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;

/**
 * 使用ASM实现AOP功能
 */
public class ASMAop
{
	public static void main(String[] args)throws Exception
	{
		ClassReader cr = new ClassReader("com.agent.my5.Operation");
		ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
		cr.accept(new LogClassVisitor(cw), ClassReader.SKIP_DEBUG);
		
		Class<?> clazz = new MyClassLoader().defineClassForName("com.agent.my5.Operation", cw.toByteArray());
		
		clazz.getMethods()[0].invoke(clazz.newInstance());
	}
}

class MyClassLoader extends ClassLoader {
    public MyClassLoader() {
        super(Thread.currentThread().getContextClassLoader());
    }
    public Class<?> defineClassForName(String name, byte[] data) {
        return this.defineClass(name, data, 0, data.length);
    }
}

package com.agent.my5;

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

public class LogClassVisitor extends ClassVisitor
{
	public LogClassVisitor(ClassVisitor cv)
	{
		super(Opcodes.ASM5, cv);
	}

	public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions)
	{
		if("oper".equals(name))
		{
			return new LogMethodVisitor(super.visitMethod(access, name, desc, signature, exceptions));
		}
		return super.visitMethod(access, name, desc, signature, exceptions);
	}
}

package com.agent.my5;

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

public class LogMethodVisitor extends MethodVisitor
{
	public LogMethodVisitor(MethodVisitor mv)
	{
		super(Opcodes.ASM5, mv);
	}

	public void visitCode() {
		/**
		 * 方法执行之前植入代码
		 */
		super.visitMethodInsn(Opcodes.INVOKESTATIC, "com/agent/my5/Log", "startLog", "()V", false);
		super.visitCode();
	}
	
	public void visitInsn(int opcode)
	{
		if(opcode == Opcodes.RETURN)
		{
			/**
			 * 方法return之前,植入代码
			 */
			super.visitMethodInsn(Opcodes.INVOKESTATIC, "com/agent/my5/Log", "endLog", "()V", false);
		}
		super.visitInsn(opcode);
	}
}


最后执行,输出结果如下:

start log ...
***********这里是执行的逻辑**********
end log ...

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值