几种AOP编程

1 篇文章 0 订阅

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

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() {
			@Override
			public 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;
	@Override
	public 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 setName
logging: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() {
			@Override
			public 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 xxxx
dog say: 汪汪汪
CGlib是对asm的一个包装。asm是一个优秀的字节码框架。CGlib在生成代理时,会利用asm来生成一个被代理对象的子类字节码流,然后通过加载这个字节码流,来生成代理类。这么做的好处就是不需要被代理类实现接口。通过反编译CGlib的动态代理字节码文件,会发现代理对象的方法调用不是通过反射来完成的,这样会在性能上有较大提升。

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


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

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





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值