几种AOP编程

来源:互联网 发布:账户到期 数据库 编辑:程序博客网 时间:2024/06/05 15:17

面向切面编程相信大家都熟悉这个词汇了,废话我就不说了。

1、java.lang.reflect.Proxy

用动态代理来生成一个接口对象,然后通过InvocationHandler来实现切面织入。

这个动态代理是利用ProxyGenerator.generateProxyClass根据接口生成二进制流(byte数组的形式),然后调用本地方法defineClass0加载这个byte数组,从而得到这个代理对象的Class对象。这个代理Class对象有一个构造方法,这个构造方法的参数是InvocationHandler。

然后再通过反射生成代理对象。代码示例如下

public static void main(String[] args) {final Monitor m=new Monitor("测试");Logging log=(Logging) Proxy.newProxyInstance(m.getClass().getClassLoader(), new Class[]{Logging.class}, new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {System.out.println("do xxxxx");Object o=method.invoke(m, args);System.out.println("do xxxxx end");return o;}});log.log();}
interface Logging{public void log();}class Monitor implements Logging{public Monitor(String name){this.name=name;}private String name;@Overridepublic void log() {System.out.println(" logging:"+name);}}

结果:
do xxxxx logging:测试do xxxxx end

优点:使用简单。仅用jdk就能完成不需要其他jar

缺点:从Proxy的代码来看,他的aop编程是基于代码运行时生成代理,然后在这个代理上做切面织入的。而且每次调用方法,都会使用反射,所以性能上不太好。


2、AspectJ

AspectJ是基于在编译期将切面织入字节码文件的。所以对于AspectJ的aop来说,不存在大量反射影响性能的情况。


切面代码

public aspect BoundPerson { pointcut log(Person p) : call(public void Person.*(*))&&target(p); after(Person p) returning() : log(p){  System.out.println(thisJoinPoint.getSourceLocation()+" "+thisJoinPoint.getSignature().getName());  System.out.println("logging:"+p.getName()); }}
被织入的对象

public class Person { private String name;  public String getName(){ return name;} public void setName(String name){  this.name=name; } public static void main(String a[]){  new Person().setName("haha"); }}
运行结果

Person.java:12 setNamelogging:haha
AspectJ的编程有自己的一套规范,对于java开发者来说不难掌握。AspectJ的编译器实际上就是运行一个java程序,将aspect文件加载后并解析。然后根据这个文件内容,去修改切面的字节码文件,来达到织入的效果。

优点:织入语言比较清晰容易掌握。因为是编译期织入,所以运行速度比较快。

缺点:需要AspectJ编译器,加入aspectj的相关jar包才能使用。

3、CGlLib(asm包装)

这个在spring、hibernate等开源框架都有使用。

public static void main(String[] args) {final Dog dog=new Dog();Enhancer en=new Enhancer();en.setSuperclass(Dog.class);en.setCallback(new MethodInterceptor() {@Overridepublic Object intercept(Object obj, Method method, Object[] args,MethodProxy proxy) throws Throwable {System.out.println("begin xxxx");Object o=method.invoke(dog, args);return o;}});Dog d=(Dog)en.create();d.say();}
class Dog {public void say(){System.out.println("dog say: 汪汪汪");}}
运行结果

begin xxxxdog say: 汪汪汪
CGlib是对asm的一个包装。asm是一个优秀的字节码框架。CGlib在生成代理时,会利用asm来生成一个被代理对象的子类字节码流,然后通过加载这个字节码流,来生成代理类。这么做的好处就是不需要被代理类实现接口。通过反编译CGlib的动态代理字节码文件,会发现代理对象的方法调用不是通过反射来完成的,这样会在性能上有较大提升。

优点:稳定、简单、容易使用。比java.lang.reflect.Proxy性能好。不需要实现接口。


4、其他修改字节码文件框架,asm、javassit、bcel等

这几种使用起来不方便,就不介绍了





0 0
原创粉丝点击