1. 1. Java静态代理
  2. 2. Java动态代理
  3. 3. 动态代理中的命令执行

Java静态代理

Java静态代理是 Java中的一种设计模式。静态代理就是通过一个代理对象来间接访问真实对象。代理类会“代理”真实类的行为,可以在代理类中添加额外的功能或逻辑(例如日志、性能监控等),而不需要修改真实类的代码。

首先定义一个接口 subject:

1
2
3
4
5
public class Subject {
public interface request{
void request();
}
}

实现类 SubjectImpl实现接口中的 request()方法:

1
2
3
4
5
6
public class SubjectImpl implements Subject{
@Override
public void request() {
System.out.println("提交成功!");
}
}

静态代理类,代理真实的请求,加上了一些额外的处理逻辑 (更新日志等):

1
2
3
4
5
6
7
8
9
10
11
12
13
public class SubjectProxy implements Subject {
private SubjectImpl subjectImpl;
public SubjectProxy(SubjectImpl subjectimpl) {
this.subjectImpl = subjectimpl;
}

@Override
public void request() {
System.out.println("request方法被调用");
subjectImpl.request();
System.out.println("调用日志已更新");
}
}

客户类 Client使用静态代理的模式调用 request()方法:

1
2
3
4
5
6
public class Client {
public static void main(String[] args) {
Subject subjectProxy = new SubjectProxy(new SubjectImpl());
subjectProxy.request();
}
}

静态代理的好处是在不修改真实类 (subjectImpl) 的前提下,为 (request) 方法增加一些额外的功能,比如日志、缓存等。

Java动态代理

Java动态代理也是一种设计模式,由 Java JDK提供,可以减少很多重复代码,提高效率。

当 Subject接口中只有一种方法时,静态代理看起来还不错,但当 Subject接口中需要实现多种方法时,静态代理会使代码庞杂冗余:

image-20250206162717774

这种情况下使用动态代理。

InvocationHandler (调用处理器) 接口 -> 通过反射机制 (invoke方法) 动态代理对象:

image-20250206182548608

定义 SubjectInvocationHandler类通过反射进行动态代理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class SubjectInvocationHandler implements InvocationHandler {
Subject subject;

public SubjectInvocationHandler(Subject subject) {
this.subject = subject;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName() + "方法被调用");
method.invoke(subject, args);
return null;
}
}

客户端通过 Proxy.newProxyInstance创建动态代理对象,分别接收三个参数。

(1) ClassLoader loader 类加载器 (不影响 invoke的执行)。

(2) Class<?> [] interfaces 被代理的接口(s) - 数组,若指定了 interfaces,代理对象都被视为实现了 interfaces接口,调用 Interfaces接口时,都会先经过 InvocationHandler.invoke()方法。

(3) InvocatonHandler h 调用处理器对象,重写定义了 invoke()方法。

image-20250206183351588

1
2
3
4
5
6
7
8
public class DynProxyClient {
public static void main(String[] args) {
Subject subject = new SubjectImpl();
InvocationHandler subjectInvocationHandler = new SubjectInvocationHandler(subject);
Subject subjectProxy = (Subject) Proxy.newProxyInstance(subject.getClass().getClassLoader(), subject.getClass().getInterfaces(), subjectInvocationHandler);
subjectProxy.response();
}
}

动态代理中的命令执行

当 SubjectInvocationHandler.invoke()方法中存在危险函数/逻辑缺陷:

image-20250206191514346

可以利用 Map接口调用 put方法触发 SubjectInvocationHandler.invoke():

1
2
3
4
5
6
7
8
public class Evil {
public static void main(String[] args) {
Subject evilSubject = new SubjectImpl();
InvocationHandler evilInvocationHandler = new SubjectInvocationHandler(evilSubject);
Map<Object, Object> map = (Map<Object, Object>) Proxy.newProxyInstance(evilSubject.getClass().getClassLoader(), new Class[]{Map.class}, evilInvocationHandler);
map.put(1,1);
}
}