代理模式

  1. 0x00 代理模式
  2. 0x01 静态代理
  3. 0x02 JDK 动态代理
  4. 0x03 CGLIB 动态代理
  5. 0x04 对比装饰者模式

0x00 代理模式

代理模式(Proxy Pattern)是一种结构型设计模式,它为其他对象提供一个代理以控制对这个对象的访问。代理模式的主要目的是在不直接暴露目标对象的情况下,通过代理对象来间接地操作目标对象。这样做的好处是可以增加额外的功能,比如权限检查、缓存、日志记录等,而不会修改原始对象的行为。

在 Java 中,代理模式可以通过多种方式实现,包括静态代理、动态代理(JDK 动态代理)和 CGLIB 动态代理。下面我们来分别介绍这些实现方式。

类图:

classDiagram
    class Subject {
        +request()
    }
    class RealSubject {
        +request()
    }
    class ProxySubject {
        +request()
    }
    class Client {
        +main()
    }
    Subject <|-- "实现" RealSubject
    Subject <|-- "实现" ProxySubject
    RealSubject o-- "聚合" ProxySubject
    Client ..> ProxySubject

0x01 静态代理

静态代理是最简单的代理模式实现,它要求我们手动创建代理类,并且需要知道目标对象的接口。下面是一个简单的静态代理的例子:

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
// 定义一个接口
interface Subject {
void request();
}

// 实现接口的目标对象
class RealSubject implements Subject {
@Override
public void request() {
System.out.println("RealSubject: Handling request.");
}
}

// 实现接口的代理对象
class ProxySubject implements Subject {
private RealSubject realSubject;

public ProxySubject(RealSubject realSubject) {
this.realSubject = realSubject;
}

@Override
public void request() {
System.out.println("Proxy: Before request.");
realSubject.request();
System.out.println("Proxy: After request.");
}
}

// 客户端代码
public class Client {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
Subject proxy = new ProxySubject(realSubject);
proxy.request();
}
}

0x02 JDK 动态代理

JDK 动态代理允许我们在运行时动态地创建一个代理对象。为了使用 JDK 动态代理,我们需要实现 InvocationHandler 接口,并使用 Proxy.newProxyInstance() 方法来创建代理对象。下面是一个使用 JDK 动态代理的例子:

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
45
46
47
48
49
50
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// 定义一个接口
interface Subject {
void request();
}

// 实现接口的目标对象
class RealSubject implements Subject {
@Override
public void request() {
System.out.println("RealSubject: Handling request.");
}
}

// 动态代理类,实现 InvocationHandler 接口
class DynamicProxy implements InvocationHandler {
private Object target;

public DynamicProxy(Object target) {
this.target = target;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("DynamicProxy: Before request.");
Object result = method.invoke(target, args);
System.out.println("DynamicProxy: After request.");
return result;
}

public Subject getProxy() {
return (Subject) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this);
}
}

// 客户端代码
public class Client {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
Subject proxy = new DynamicProxy(realSubject).getProxy();
proxy.request();
}
}

0x03 CGLIB 动态代理

CGLIB 是一个高性能的代码生成库,它可以被用来动态地创建代理对象,即使目标对象没有实现任何接口。CGLIB 通过继承的方式实现动态代理,因此它可以代理那些没有实现接口的类。下面是使用 CGLIB 创建代理的一个例子:

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
45
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

// 目标对象
class RealSubject {
public void request() {
System.out.println("RealSubject: Handling request.");
}
}

// CGLIB 动态代理类
class CglibProxy implements MethodInterceptor {
private Object target;

public CglibProxy(Object target) {
this.target = target;
}

public Object getProxy() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}

@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("CglibProxy: Before request.");
Object result = methodProxy.invokeSuper(proxy, args);
System.out.println("CglibProxy: After request.");
return result;
}
}

// 客户端代码
public class Client {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
RealSubject proxy = (RealSubject) new CglibProxy(realSubject).getProxy();
proxy.request();
}
}

0x04 对比装饰者模式

代理模式vs装饰器模式

文章标题:代理模式

本文作者:zhu8fei

发布时间:2024-08-15, 16:57:52

最后更新:2024-08-16, 18:17:58

原始链接:http://www.zhu8fei.com/2024/08/15/proxy-pattern.html

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 zhu8fei@163.com

目录
×

喜欢就点赞,疼爱就打赏