1.目的:实现对函数执行监听,在函数调用前,后得到通知。考虑用asm来实现。
2.资料:在网上看到关于asm的技术资料,写了一个简单的实现。参考链接如下:
[url]http://www.cnblogs.com/eafy/archive/2008/06/18/1224633.html[/url]
[url]http://alvinqq.iteye.com/blog/940965[/url]
[url]http://www.ibm.com/developerworks/cn/java/j-lo-asm30/[/url]
[url]http://ayufox.iteye.com/blog/668917[/url]
3.代码:asmAopClassAdapter 该类对目标类进行操作。
asmAopMethodAdapter 对目标类的方法做操作。
ChangeToChildConstructorMethodAdapter该类生成目标类的子类。
asmAopGenerator 一个工具类,生成代理目标类的对象。
asmAopInvoker 函数注入类
测试类
输出结果
4.目的基本达成。
5.待改进,在监听函数执行后,是用的try和catch抛异常的方式来实现。
6.环境 asm 3.3.1 jdk 1.6.
2.资料:在网上看到关于asm的技术资料,写了一个简单的实现。参考链接如下:
[url]http://www.cnblogs.com/eafy/archive/2008/06/18/1224633.html[/url]
[url]http://alvinqq.iteye.com/blog/940965[/url]
[url]http://www.ibm.com/developerworks/cn/java/j-lo-asm30/[/url]
[url]http://ayufox.iteye.com/blog/668917[/url]
3.代码:asmAopClassAdapter 该类对目标类进行操作。
public class asmAopClassAdapter extends ClassAdapter{
private String enhancedSuperName,enhancedName;
private String method;
private String startInfo,endInfo;
public asmAopClassAdapter(ClassVisitor cv,String methodName,String start,String end) {
//Responsechain 的下一个 ClassVisitor,这里我们将传入 ClassWriter,
// 负责改写后代码的输出
super(cv);
method = methodName;
startInfo = start;
endInfo = end;
}
// 重写 visitMethod,访问到 "method" 方法时,
// 给出自定义 MethodVisitor,实际改写方法内容
public MethodVisitor visitMethod(final int access, final String name,
final String desc, final String signature, final String[] exceptions) {
MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions);
MethodVisitor wrappedMv = mv;
if (mv != null) {
if (name.equals(method)) {
wrappedMv = new asmAopMethodAdapter(mv,startInfo,endInfo);
} else if (name.equals("<init>")) {
wrappedMv = new ChangeToChildConstructorMethodAdapter(mv,
enhancedSuperName);
}
}
return wrappedMv;
}
public void visit(final int version, final int access, final String name,
final String signature, final String superName,
final String[] interfaces) {
enhancedName = name.replace("/", "$")+"$EnhancedByASM"; // 改变类命名
enhancedSuperName = name; // 改变父类
super.visit(version, access, enhancedName, signature,
enhancedSuperName, interfaces);
}
public String getEnhancedName() {
return enhancedName;
}
}
asmAopMethodAdapter 对目标类的方法做操作。
public class asmAopMethodAdapter extends MethodAdapter implements Opcodes{
private final static int EXCEPTION_STACK = 2 + 1;//max_stack至少需要能够容纳2个常量地址(监控方法使用)和1个exception地址
private Label try_catch_start,try_catch_end;
private String startInfo,endInfo;
public asmAopMethodAdapter(MethodVisitor mv,String start,String end) {
super(mv);
try_catch_start = new Label();
try_catch_end = new Label();
startInfo = start;
endInfo = end;
}
public void visitCode() {
mv.visitCode();
mv.visitLabel(try_catch_start);
mv.visitLdcInsn(startInfo);
//asmAopInvoker 这里写类的路径例如:com.asm.asmAopInvoker 应写成 com/asm/asmAopInvoker
mv.visitMethodInsn(INVOKESTATIC, "asmAopInvoker",
"methodStart", "(Ljava/lang/String;)V");
}
public void visitInsn(int opcode){
if(opcode >= IRETURN && opcode <= RETURN){
mv.visitLdcInsn(endInfo);
//asmAopInvoker 这里写类的路径例如:com.asm.asmAopInvoker 应写成 com/asm/asmAopInvoker
mv.visitMethodInsn(INVOKESTATIC, "asmAopInvoker",
"methodEnd", "(Ljava/lang/String;)V");
}
mv.visitInsn(opcode);
}
public void visitEnd() {
mv.visitLabel(try_catch_end);
mv.visitTryCatchBlock(try_catch_start, try_catch_end, try_catch_end, null);
mv.visitLdcInsn(endInfo);
//asmAopInvoker 这里写类的路径例如:com.asm.asmAopInvoker 应写成 com/asm/asmAopInvoker
mv.visitMethodInsn(INVOKESTATIC, "asmAopInvoker",
"methodEnd", "(Ljava/lang/String;)V");
mv.visitInsn(Opcodes.ATHROW);
mv.visitEnd();
}
public void visitMaxs(int maxStack,int maxLocals){
//保证max stack足够大
mv.visitMaxs(Math.max(EXCEPTION_STACK,maxStack), maxLocals);
}
}
ChangeToChildConstructorMethodAdapter该类生成目标类的子类。
public class ChangeToChildConstructorMethodAdapter extends MethodAdapter {
private String superClassName;
public ChangeToChildConstructorMethodAdapter(MethodVisitor mv,
String superClassName) {
super(mv);
this.superClassName = superClassName;
}
public void visitMethodInsn(int opcode, String owner, String name,
String desc) {
// 调用父类的构造函数时
if (opcode == Opcodes.INVOKESPECIAL && name.equals("<init>")) {
owner = superClassName;
}
super.visitMethodInsn(opcode, owner, name, desc);// 改写父类为 superClassName
}
}
asmAopGenerator 一个工具类,生成代理目标类的对象。
public class asmAopGenerator {
private AOPGeneratorClassLoader classLoader ;
public asmAopGenerator(){
classLoader = new AOPGeneratorClassLoader();
}
public Object proxy(Class c,String methodName,String startInfo,String endInfo) {
try{
if( c != null){
String classPach = c.toString().replace("/", ".");
ClassReader cr = new ClassReader(classPach.substring(6,classPach.length()));
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
asmAopClassAdapter classAdapter = new asmAopClassAdapter(cw,methodName,startInfo,endInfo);
cr.accept(classAdapter, ClassReader.SKIP_DEBUG);
byte[] data = cw.toByteArray();
Class obj = classLoader.defineClassFromClassFile(classAdapter.getEnhancedName(), data);
//TODO:隐藏BUG
return obj.newInstance();
}}catch(Exception e){
e.printStackTrace();
}
return null;
}
class AOPGeneratorClassLoader extends ClassLoader {
public Class defineClassFromClassFile(String className,
byte[] classFile) throws ClassFormatError {
return defineClass(className, classFile, 0,
classFile.length);
}
}
}
asmAopInvoker 函数注入类
public class asmAopInvoker {
public static void methodEnd(String evtID){
System.out.println(evtID);
}
public static void methodStart(String evtID){
System.out.println(evtID);
}
}
测试类
public class helloWorld {
public void sayHello(){
System.out.println("helloWorld....");
}
public static void main(String[]args){
asmAopGenerator aag = new asmAopGenerator();
helloWorld hw = (helloWorld) aag.proxy(helloWorld.class, "sayHello", "it's begin", "it's end");
hw.sayHello();
}
}
输出结果
it's begin
helloWorld....
it's end
4.目的基本达成。
5.待改进,在监听函数执行后,是用的try和catch抛异常的方式来实现。
6.环境 asm 3.3.1 jdk 1.6.