目前实现AOP最常见,最简单的方法就是Propxy模式,写一个代理类,代理类里面持有真实类的引用。
这种方式实现的AOP,多了一层包装
使用ASM的话,就不需要多一层包装了,它是直接把代码植入到class文件里面(严格上说是字节码中)
现在需要对这个类的oper方法做aop,在方法执行之前执行如下类的startLog()方法,方法执行结束后,执行endLog()方法
这种方式实现的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 ...