设计模式-代理模式

代理模式

为其他对象提供一种代理以控制对这个对象的访问。

组成

(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
//InvocationHandler + invoke()
public class Proxy implements InvocationHandler {


// 被代理类的实例
Object obj;

// 将被代理者的实例传进动态代理类的构造函数中
public Proxy(Object obj) {

this.obj = obj;
}

/**
* 覆盖InvocationHandler接口中的invoke()方法
* 更重要的是,动态代理模式可以使得我们在不改变原来已有的代码结构
* 的情况下,对原来的“真实方法”进行扩展、增强其功能,并且可以达到
* 控制被代理对象的行为,下面的before、after就是我们可以进行特殊
* 代码切入的扩展点了。
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
/*
* before :doSomething();
*/
Object result = method.invoke(this.obj, args);

/*
* after : doSomething();
*/
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
//MethodIntercepter + intercept()
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..."); }
}
文章目录
  1. 1. 代理模式
    1. 1.1. 组成
    2. 1.2. 代理模式的应用
    3. 1.3. 应用实例
    4. 1.4. 优点
    5. 1.5. 缺点
    6. 1.6. 静态代理
    7. 1.7. 动态代理
    8. 1.8. (1)jdk动态代理:接口+InvocationHandler+目标对象
    9. 1.9. (2)cglib动态代理:接口或类+MethodInterceptor+目标对象
| 139.6k