转载于:http://www.blogjava.net/henry1451/archive/2008/07/10/214004.html
还可以参考:
http://www.blogjava.net/hadeslee/archive/2007/09/08/143641.html
http://blog.csdn.net/yygywqf/article/details/4044812
http://kuangbaoxu.iteye.com/blog/193240
http://zhangjunhd.blog.51cto.com/113473/69996
今天读了读夏昕写的《Spring开发指南》,在“AOP in Spring”一节,作者讲述了Spring中如何通过动态AOP来提供内置的AOP支持。“从技术角度来讲,所谓动态AOP,即通过动态Proxy模式,在目标对象的方法调用前后插入相应的处理代码”
作者举了一些例子来解释何为静态Proxy,何为动态Proxy。奈何我根基尚浅,最作者举的动态Proxy的例子懵懂不解,于是自己尝试着摸索一番,终于对动态Proxy的用法有了一个初步的认识。
首先还是来看静态Proxy,就我目前的认识看来,Proxy的主要用途是对类中方法的执行进行一下包装,在方法执行之前,或之后,或both,加入一些“额外”的操作。典型的应用就是加入事务处理。
静态Proxy相对来讲比较简单,它是对上面所述思想的一个最直接的实现。
假设我们现在有如下一个接口:
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1fa987a29c6482f53d401256f96355eb.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/8f1ba5b45633e9678d1db480c16cae3f.gif)
以及该接口的一个实现类:
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1fa987a29c6482f53d401256f96355eb.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/ecedf933ec37d714bd4c2545da43add2.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/8f1ba5b45633e9678d1db480c16cae3f.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
那么很容易,我们可以通过如下方式进行调用:
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1fa987a29c6482f53d401256f96355eb.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/ecedf933ec37d714bd4c2545da43add2.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/ecedf933ec37d714bd4c2545da43add2.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/8f1ba5b45633e9678d1db480c16cae3f.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
输出结果:
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
现在问题来了:如果现在我们想在getMessage()之外添加一些额外的操作,比如在这之前输出“Begin”,在之后输出“done”,但又不能改变原有接口,怎么办?也很简单,用静态Proxy就可以很方便的实现:
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1fa987a29c6482f53d401256f96355eb.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/ecedf933ec37d714bd4c2545da43add2.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/ecedf933ec37d714bd4c2545da43add2.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/8f1ba5b45633e9678d1db480c16cae3f.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
调用:
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1fa987a29c6482f53d401256f96355eb.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/ecedf933ec37d714bd4c2545da43add2.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/ecedf933ec37d714bd4c2545da43add2.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/8f1ba5b45633e9678d1db480c16cae3f.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
结果:
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
你可以看到,StaticProxy只是在Foo的某实现类基础上包了一层,当然我们这里加的两个输出语句无足轻重,但如果我们把这两个输出语句替换成事务处理,意义就大不一样了。
可见,通过静态Proxy可以实现我们的需求,但如果我们有十几、二十个这样的接口实现类,需要类似的处理,我们怎么办?难道每个实现类都对应一个Proxy吗?
这时,我们就需要动态Proxy:
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1fa987a29c6482f53d401256f96355eb.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/ecedf933ec37d714bd4c2545da43add2.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/ecedf933ec37d714bd4c2545da43add2.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/8f1ba5b45633e9678d1db480c16cae3f.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
第一次看到上面的代码肯定不知所以,稍后解释,我们先看如何调用:
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1fa987a29c6482f53d401256f96355eb.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/ecedf933ec37d714bd4c2545da43add2.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/ecedf933ec37d714bd4c2545da43add2.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/8f1ba5b45633e9678d1db480c16cae3f.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
结果:
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
下面来解释一下AOPHandler这个类:
首先,bind()方法是用来创建动态Proxy实例。动态Proxy也是Proxy,和静态Proxy一样,功能上都是为了在调用某接口实现类的方法之余,添加一些额外的操作(比如事务处理),他们(动态和静态Proxy)都是一种特殊的接口实现类。因此,我们在调用的时候可以用
String message = ((Foo) proxy).getMessage("Wing");
把proxy实例直接cast为Foo类型,并调用foo接口上的方法。
不同的是,静态Proxy,正如前面看到的,是直接实现了接口,并在接口的方法中直接调用该接口某实现类对应的方法。而动态Proxy,是利用Java.lang.reflect.Proxy类提供的这样一种机制:当构建Proxy时,我们需要提供接口,以及一个关联的调用处理程序对象(通常实现了InvocationHandler接口),当我们在Proxy上调用接口上的方法(任意方法)时,将触发调用InvocationHandler接口定义的invoke()方法,由invoke方法完成相应的操作。
上面的AOPHandler类,是将动态Proxy的构建与InvocationHandler接口的实现结合在了一起。
通过AOPHandler,我们可以在运行时期动态的决定用哪个接口实现类来创建Proxy,而不需事先为每个实现类定义对应的Proxy,灵活性和复用性大大增强。
进一步的,我们可以利用java反射机制,通过类名来得到接口实现类的实例,进而得到该实例的动态Proxy。这样我们就可以在配置文件里动态指定需要用到的接口实现类,就像Spring中所做的一样。