代理模式

本文最后更新于 2025年7月26日 中午

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

在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介作用。

角色

  1. 抽象主题角色 : 抽象主题类的主要职责是声明真实主题与代理的共同接口方法,该类可以是接口也可以是抽象类
  2. 真实主题角色 : 该类也称为被代理类,定义了代理所表示的真实对象,是负责执行系统真正逻辑的业务对象
  3. 代理主题角色 : 也称为代理类,其内部持有RealSubject的引用,因此完全具备对RealSubject的代理权。客户端调用代理对象的方法,同时也调用被代理对象的方法。

分类

  1. 静态代理:由程序创建或特定工具自动生成源代码,在程序运行前,代理类的.class文件已经存在
  2. 动态代理:在程序运行时,运用反射机制动态创建而成,无须手动编写代码

场景

  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
45
46
47
48
49
50
51
52
53
54
55
56
// 统一的接口
public interface UserService {
void saveUser();

Object findUser(int uid);

}

// 被代理类定义
public class UserServiceImpl implements UserService{
@Override
public void saveUser(){
System.out.println("调用DAO保存用户信息");
}

@Override
public Object findUser(int uid){
System.out.println("调用DAO查询用户信息");
return "user{name:'codfish'}";
}
}

// 静态代理扩展
public class UserServiceProxy implements UserServices {
private UserService userService ;

public class UserServiceProxy(UserService userService){
this.userService = userService;
}

@Override
public void saveUser(){
long startTime = System.currentTimeMillis();
userService.saveUser();
long endTime = System.currentTimeMillis();
System.out.println("saveUser方法耗时:" + (endTime-startTime));
}

@Override
public Object findUser(int uid){
long startTime = System.currentTimeMillis();
Object rs = userService.findUser(uid);
long endTime = System.currentTimeMillis();
System.out.println("findUser 方法耗时:" + (endTime - startTime));
return rs ;
}
}

// 调用
public class Test{
public static void main(String[] args){
UserService userService = new UserServiceProxy(new UserServiceImpl());
userService.saveUser();
userService.findUser();
}
}

动态代理

普通的静态代理,只能在同一接口定义下,完成对被代理类的代理过程。

这时可以使用动态代理,来对在编码时不确定具体接口,类信息的对象进行动态代理。

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
// 实现InvocationHandler 接口,重写invoke 方法,创建动态代理

public class JDKProxy implements InvocationHandler {
private Object target ;
Object proxy = Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this
);
@Override
public Object invoke(Object proxy , Method method, Object[] args) throws Throwable{
long startTime = System.currentTimeMillis();
Object rs = method.invoke(target , args);
long endTime = System.currentTimeMillis();
System.out.println("JDK Proxy耗时:" + (endTime-startTime));
return rs ;
}
}

// 调用
public class Test{
public static void main(String[] args){
JDKProxy jdkProxy = new JDKProxy();
UserService userService = (UserService)jdkProxy.bind(new UserServiceImpl());
userService.saveUser();
userService.findUser();
}
}

这样就可以在不修改原有对象的基础上,完成对原对象方法的调用

JDK实现的动态代理的缺点是 被代理类必须实现了接口。

而另一种方式是 通过使用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
// 被代理类
public class UserService {
public void saveUser() {
System.out.println("保存用户");
}

public void findUser() {
System.out.println("查找用户");
}
}

// 使用 CGLIB Proxy 进行代理
public class CglibProxy implements MethodInterceptor {

private Object target;

public Object bind(Object target) {
this.target = target;

Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass()); // 设置父类(目标类)
enhancer.setCallback(this); // 设置回调
return enhancer.create(); // 创建代理对象
}

@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
long startTime = System.currentTimeMillis();
Object rs = proxy.invoke(target, args); // 调用目标对象的方法
long endTime = System.currentTimeMillis();
System.out.println("CGLIB Proxy耗时:" + (endTime - startTime));
return rs;
}
}

// 调用
public class Test {
public static void main(String[] args) {
CglibProxy cglibProxy = new CglibProxy();
UserService userService = (UserService) cglibProxy.bind(new UserService());
userService.saveUser();
userService.findUser();
}
}

CGLIB 是通过创建被继承类的子类来完成代理过程的,所以在使用CGLiB 进行动态代理创建的时候,无法为被final 修饰的类创建动态代理。

总结

代理模式通过引入一个代理对象,在不修改目标对象的前提下,控制对目标对象的访问或增强其功能。它将请求的发起与实际执行进行解耦,常用于权限控制、延迟加载、远程调用与功能扩展等场景。代理模式包括静态代理和动态代理两种形式,静态代理在编译期生成代码,适合结构清晰的场景;动态代理则在运行时生成代理类,更加灵活,常用于 AOP 和框架设计中,是实现开闭原则和职责分离的重要手段。


代理模式
http://gadoid.io/2025/07/26/代理模式/
作者
Codfish
发布于
2025年7月26日
许可协议