代理模式和动态代理
代理模式:
为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。
组成:
- Subject:proxy 和 RealSubject 的公共对外方法
- RealSubject:真实实现逻辑的类,对Client不可见
- Proxy:用来代理和封装 RealSubject
- Client:使用 Subject 和 Proxy 完成工作
使用举例
1. 延迟加载
假设有个功能组件,初始化它十分耗费资源。实际情况中,如果该组件未被实际使用,则该初始化属于资源浪费。因此,我们可以考虑如果当前并没有使用这个组件,则不需要真正地初始化它,先使用一个代理对象替代它的原有的位置,只要在真正需要的时候才对它进行加载。
下面用一个数据库查询的操作作为例子(假设查询前需要连接数据库比较耗时)
|
|
2. 方法执行前后增加额外操作
类似上述数据库查询的例子,要求记录每次request的操作时间。(这个例子不考虑加载慢的问题)
|
|
上述的两个例子都属于静态代理,静态代理也是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。(因为我们编写了固定的类来实现代理)
动态代理
动态代理是指在运行时动态生成代理类。和静态代理相比,动态代理不需要为 RealSubject 写一个形式完全一样的封装类(Proxy),方便维护。其次,使用一些动态代理的生成方法甚至可以在运行时制定代理类的执行逻辑,从而大大提升系统的灵活性。
动态代理使用字节码动态生成加载技术,方法有很多。这里介绍下 JDK自带的动态代理,CGLIB。
JDK自带的动态代理
JDK 的动态代理使用简单,它内置在 JDK 中,因此不需要引入第三方 Jar 包,但相对功能比较弱,只能针对实现了接口的类生成代理。
以下使用 core java 中的打印执行方法的例子:
|
|
CGLIB
CGLIB 和 Javassist 都是高级的字节码生成库,总体性能比 JDK 自带的动态代理好,而且功能十分强大。
(CGLIB 是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的所有方法,所以该类或方法不能声明成final的。)
使用CGLIB来实现上述 方法执行前后增加额外操作 的例子:
|
|