javassist AOP
2016-03-24 16:47
423 查看
对于AOP,这个概念,不用解释,主要用途很多,我这里主要是为了后续研究如何实现APM做准备。前面研究了动态代理实现AOP,考虑到性能的问题,改用javassist直接修改直接码实现!
javassist的使用,可以参考官网, 在用eclipse开发程序的时候,要将这个javassist的jar包放入classpath下。若基于maven开发的话,也有对应的maven插件,很简单的事情!
下面主要列举一下常用的类以及方法:
另外还有CtMethod,CtField等等,这些可以到官网找相关的API文档了解其使用方法。下面通过一个简单的例子看看如何使用javassist来动态编写程序,实现AOP。
先定义一个业务类Feed.java,其中的函数,就好比是我们业务系统中的某个操作。
接下来,定义一个测试类,在这个测试类里面,通过javassist的函数调用,实现切面织入,也就是AOP的目的所在。这个类TEST.java:
上面的代码执行完后,可以看到下面的结果:
上述代码中$$表示所有的参数,关于javassist的函数调用中参数传递,可以参考官网的说明,这里截取一部分,可以先有个概念,这个和shell脚本中的function调用是参数传递非常像!
虽然javassist的使用中也涉及到了反射的使用,大家都应该意识到,在产品级的软件中,若大量使用反射,性能是不会好的,当然javassist的官方组织也知道这点,所以,在使用的时候,可以通过定义interface,然后在javassist中动态编程来实现这个接口中的方法,调用方,通过这个接口来调用方法,这样就可以绕开因为反射造成的性能损失。
另外,javassist的深入灵活的使用,后续再继续研究,并及时更新博客!
javassist的使用,可以参考官网, 在用eclipse开发程序的时候,要将这个javassist的jar包放入classpath下。若基于maven开发的话,也有对应的maven插件,很简单的事情!
下面主要列举一下常用的类以及方法:
获取JVM中已经加载的所有的类的集合,即pool ClassPool pool = ClassPool.getDefault(); 获取指定类名对应的类 CtClass cc = pool.get("带有包名的全路径类名"); 为这个类设置超级类 cc.setSuperclass(pool.get("指定带有全路径的类名"));
另外还有CtMethod,CtField等等,这些可以到官网找相关的API文档了解其使用方法。下面通过一个简单的例子看看如何使用javassist来动态编写程序,实现AOP。
先定义一个业务类Feed.java,其中的函数,就好比是我们业务系统中的某个操作。
package javassit_aop; /** * * @author shihuc * @date Mar 24, 2016 * */ public class Feed { public void forTest(){ System.out.println("----------execute function \"forTest()\"-----------"); } }
接下来,定义一个测试类,在这个测试类里面,通过javassist的函数调用,实现切面织入,也就是AOP的目的所在。这个类TEST.java:
package javassit_aop; import javassist.CannotCompileException; import javassist.ClassPool; import javassist.CtClass; import javassist.CtMethod; import javassist.CtNewMethod; import javassist.NotFoundException; /** * * @author shihuc * @date Mar 24, 2016 * */ public class TEST { public static void main(String[] args) throws NotFoundException, CannotCompileException, InstantiationException, IllegalAccessException{ CtClass ctClass=ClassPool.getDefault().get("javassit_aop.Feed"); String oldName="forTest"; CtMethod ctMethod=ctClass.getDeclaredMethod(oldName); String newName=oldName+"$NewImpl"; ctMethod.setName(newName); CtMethod newMethod=CtNewMethod.copy(ctMethod, "forTest", ctClass, null); StringBuffer sb=new StringBuffer(); /* * Here, below StringBuffer is to create the new method body, what you read is the source code, * but, it will be translated to byte code which can be interpreted by JVM. * * To some extent, ".append(newName+"($$);\n")" can be said as function call to the business function Feed.forTest() */ sb.append("{System.out.println(\"Here you can do BEFORE operation\");\n") .append(newName+"($$);\n") .append("System.out.println(\"Here you can do AFTER operation\");\n}"); newMethod.setBody(sb.toString()); /* * Add new method */ ctClass.addMethod(newMethod); /* * Class changed, ATTENTION, do not use "A a = new A();" to make a new instance, * because in the same classloader it do not allow to load one class more than once. */ Feed a=(Feed)ctClass.toClass().newInstance(); a.forTest(); } }
上面的代码执行完后,可以看到下面的结果:
Here you can do BEFORE operation ----------execute function "forTest()"----------- Here you can do AFTER operation
上述代码中$$表示所有的参数,关于javassist的函数调用中参数传递,可以参考官网的说明,这里截取一部分,可以先有个概念,这个和shell脚本中的function调用是参数传递非常像!
The String object passed to the methods insertBefore(), insertAfter(), addCatch(), and insertAt() are compiled by the compiler included in Javassist. Since the compiler supports language extensions, several identifiers starting with $ have special meaning: $0, $1, $2, ... this and actual parameters $args An array of parameters. The type of $args is Object[]. $$ All actual parameters. For example, m($$) is equivalent to m($1,$2,...) $cflow(...) cflow variable $r The result type. It is used in a cast expression. $w The wrapper type. It is used in a cast expression. $_ The resulting value $sig An array of java.lang.Class objects representing the formal parameter types. $type A java.lang.Class object representing the formal result type. $class A java.lang.Class object representing the class currently edited.
虽然javassist的使用中也涉及到了反射的使用,大家都应该意识到,在产品级的软件中,若大量使用反射,性能是不会好的,当然javassist的官方组织也知道这点,所以,在使用的时候,可以通过定义interface,然后在javassist中动态编程来实现这个接口中的方法,调用方,通过这个接口来调用方法,这样就可以绕开因为反射造成的性能损失。
另外,javassist的深入灵活的使用,后续再继续研究,并及时更新博客!
相关文章推荐
- Ajax实战项目1 验证用户的唯一性 环境(Ajax+struts2)
- Java中的序列化Serialable高级详解
- 关于java.lang.IllegalArgumentException: View not attached to window manager 错误的分析
- spring学习笔记(6)AOP前夕[1]jdk动态代理实例解析
- java.不使用for,while循环打印99乘法表
- Map接口的实现类--Hashtable和HashMap及TreeMap的区别--------(java复习)
- spring mvc 基于注解的使用总结
- springMVC 整合ueditor
- java数据库连接池之bonecp
- struts2架构图
- Java学习笔记(一)之―认识JDK、JRE、JVM
- Exception_JDK安装Error opening registry key...
- Java内存管理
- JAVA内部类
- JAVA内部类
- Eclipse报错:Setting property 'source' to 'org.eclipse.jst.jee.server:test1' did no
- springMVC 上传文件同时传递参数
- 把Java数组转换为List时的注意事项
- Java IO:IO框架
- java.io.FileNotFoundException-再次踩坑windows编码