最近在学习spring,其中大量使用了动态代理技术来增强Bean的功能。所以有必要捋一捋动态代理。
1、代理
代理是一种经典的设计模式,访问控制、远程过程调用、AOP都是使用代理的场景。如果对这种设计模式不熟悉,建议参考《Java设计模式》的第11章,里面也有动态代理的内容。
2、java 的动态代理动态在哪里?
我们一般创建代理时的顺序是:
- 知道要代理谁,假设为A
- 创建代理对象,假设为B,继承A,并让B持有A的一个实例。
- 让B实现与A相同的public方法,在里面调用A对应的方法,此时可以做很多文章,比如打log,验证参数等,这些行为是我们创建代理的核心目的,毕竟代理不是简单的传声筒。我们暂且将这些行为称为代理目的。
动态代理是反过来的,它是首先知道代理目的,据此实现一个类H,将代理目的的相关代码写进去。这个类H要有一个Object 类型的成员,用来表示要代理的对象。用Object,表示可以代理任何对象。
然后,实例化类H,传入要代理的具体对象,生成h对象,将h对象和要代理原对象哪些public方法的信息(通过提供接口的方式)一起交给另一个类Proxy,Proxy会根据public方法的信息和h对象揉和在一起生成一个代理类$Proxy,并同时实例化该类,生成proxy对象,这个proxy就跟我们按照传统方式手写的代理对象是一样的。
可见,所谓动态,在于真正的代理类是在程序运行的时候由Proxy这个牛叉的类生成的。类生成类就是字节码生成技术。这个牛叉的类只需要告诉它代理原对象的哪些public方法(通过接口的形式)和具体的代理行为,即h对象,就可以work了。
H其实就是实现java.lang.reflect.InvocationHandler接口的类。该接口的方法invoke就是我们填写代理目的代码的地方。
Proxy类其实就是java.lang.reflect.Proxy。该类有一个静态方法newProxyInstance,就是接收h对象和要代理原对象哪些pubic方法的地方。
3、局限性
java动态代理的局限性在于,我们告诉Proxy要代理哪些方法时,只能通过原对象实现的接口的方式。就是说,原对象那些不是实现接口的public方法,是没办法通过这种技术来代理的。所以才有了CGLIB这种技术。
4、没有例子吗?
http://www.importnew.com/27772.html 这里有。
之前推荐的《Java设计模式》中也有。
《深入理解Java虚拟机》中也有。应该够了。
本文的目的在于总结自己对于动态代理的理解,嗯,好像达到了。