代理模式
为其他对象提供一种代理以控制对这个对象的访问。
组成
(1)抽象角色(Subject):通过接口或抽象类声明真实角色实现的业务方法。
(2)代理角色(Proxy):实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
(3)真实角色(RealSubject):实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。
代理模式的应用
(1)远程代理。为一个位于不同的地址空间的对象提供一个本地的代理对象。这个不同的地址空间可以是在同一台主机中,也可是在另一台主机中,远
程代理又叫做大使(Ambassador)。这样可以隐藏一个对象存在于不同地址空间的事实,使得客户端可以访问在远程机器上的对象。
(2)虚拟代理。根据需要创建开销很大的对象。如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时
才会被真正创建。
(3)安全代理。用来控制真实对象访问时的权限。
(4)智能指引。当调用真实对象时,代理处理另外的一些事。
应用实例
Spring 的AOP
优点
职责清晰: 真实角色就是实现实际的业务逻辑,不用关心其他非本职的事物
高扩展性: 真实角色可以随时更换或扩展,只需要实现接口就行,而代理不需要有任何变化
缺点
(1)由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。
(2)实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
静态代理
由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| public class ProxyTest { public static void main(String[] args) { Proxy proxy=new Proxy(); proxy.Request(); } }
interface Subject { void Request(); }
class RealSubject implements Subject { public void Request() { System.out.println("访问真实主题方法..."); } }
class Proxy implements Subject { private RealSubject realSubject; public void Request() { if (realSubject==null) { realSubject=new RealSubject(); } preRequest(); realSubject.Request(); postRequest(); } public void preRequest() { System.out.println("访问真实主题之前的预处理。"); } public void postRequest() { System.out.println("访问真实主题之后的后续处理。"); } }
|
动态代理
在实现阶段不需要关心代理谁,在运行阶段会动态生成一个代理类去代理指定的对象
默认的策略是如果目标类是接口,则使用JDK动态代理技术,否则使用CGlib来生成代理
(1)jdk动态代理:接口+InvocationHandler+目标对象
1 2 3 4 5 6 7
| 主要用到java.lang.reflect中的两个类:'Proxy和InvocationHandler' InvocationHandler是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类代码,动态的将横切逻辑与业务逻辑编织在一起 1.定义业务逻辑接口 2.实现业务逻辑接口创建业务实现类 3.实现(implements)InvacationHandler代理接口,创建代理类 4.创建业务类和代理类对象,通过代理类对象.bind(业务类对象)返回一个动态代理对象,然后通过动态代理对象对方法进行调用。 缺点:要求目标类必须实现对应方法非接口,它只能为接口创建代理
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| public class Proxy implements InvocationHandler {
Object obj;
public Proxy(Object obj) {
this.obj = obj; }
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(this.obj, args);
return result; } }
|
(2)cglib动态代理:接口或类+MethodInterceptor+目标对象
1 2 3 4 5
| 主要用到java.lang.reflect中的两个类:'MethodInterceptor和CglibProcy' 1.定义业务类,无需实现接口(也可以实现) 2.实现MethodInterceptor方法代理接口,创建代理类 3.创建业务类和代理类对象,通过代理类对象.getInstance(业务类对象)返回一个动态代理对象,然后通过动态代理对象对方法进行调用。 特点:能代理类和接口,但是不能代理final类
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public class Proxy implements MethodInterceptor {
private static Proxy instance = new CGLibProxy();
private Proxy() {}
public static Proxy getInstance () { return instance; }
public <T> T getProxy(Class<T> cls) { return (T) Enhancer.create(cls, this); } public Object intercept(Object obj, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { sayBefore(); Object result = methodProxy.invokeSuper(obj, objects); sayAfter(); return result; } private void sayBefore() { System.out.println("before..."); } private void sayAfter() { System.out.println("after..."); } }
|