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

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

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


首先加入asm的依赖


	org.ow2.asm
	asm-all
	5.1

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 ...

你可能感兴趣的:(框架技术)