代理模式
1. 使用场景
需要在调用者和被调用者之间加入各种控制,分离XX关注点,实现面向切面编程。
2. 实现举例
1) 权限控制
在spring security
当中,可以对目标对象方法执行前作权限检查,通过@PreAuthorize注解控制。
加了这个注解的方法所在类,spring security
会为之创建代理对象,客户真正执行的是代理对象中的方法;而代理对象中再对@PreAuthorize注解进行检查,如果有权限才间接调用目标对象方法,没权限就阻止目标对象方法的执行。
结论: 代理分离了权限关注点
2) 缓存控制
在spring
当中,可以通过@Cacheable对目标方法的返回结果进行缓存控制。
加了这个注解的方法所在类,spring
会为之创建代理对象,客户真正执行的是代理对象中的方法;而代理对象执行时再对@Cacheable注解进行解释,如果缓存中没有命中,才间接调用目标对象方法,将返回结果放入缓存;如果缓存命中,则直接返回缓存结果,而不会执行目标对象方法。
结论: 代理分离了缓存关注点
3) 事务控制
在spring
当中,可以通过@Transactional对目标方法执行前后的事务进行控制,
加了这个注解的方法所在类,spring
会为之创建代理对象,客户真正执行的是代理对象中的方法;而代理对象执行时再对@Transactional注解进行解释,在方法执行之前是开始新事务还是加入已有事务,根据方法执行是否出现了异常来决定是提交还是回滚事务。
结论: 代理分离了事务关注点
4) 方法远程调用
在方法的远程调用场景下,调用者只需像本地方法调用一样使用接口方法。
结论: 代理分离了远程访问关注点
5) 延迟实例化
比较典型的例子是hibernate
做@ManyToOne的关系映射时,为了避免产生同时进行两张表的连接查询操作,hibernate
为加了@ManyToOne的关系属性生成了代理对象。当没有用到关系属性对应的关系表数据时,不执行sql查询关系表,当第一次需要关系表数据时,才由代理对象发起一条查询语句去查关系表,从而实现了按需查询。
结论: 代理分离了延迟实例化关注点
6) 生命周期管理
有些对象的生命周期与调用者不同,需要协调。例如spring中要将生命周期较短(例如加了@RequestScope)的对象注入到生命周期更长的controller对象中。这时spring也是生成一个代理注入给controller,代理对象为每次请求生成新的对象注入给controller
结论: 代理分离了生命周期关注点
3. 特点
- 代理模式需要代理和被代理类均实现相同的接口,或者代理类作为被代理类的子类
- 代理类不会扩展原有接口或父类的功能,只是将某部分功能分出去
- 代理类一般配合工厂使用来隐藏代理对象的创建细节
- 产生代理类的手段有JDK动态代理、cglib、javassist等