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接口中需要实现多种方法时,静态代理会使代码庞杂冗余:

这种情况下使用动态代理。
InvocationHandler (调用处理器) 接口 -> 通过反射机制 (invoke方法) 动态代理对象:

定义 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()方法。

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()方法中存在危险函数/逻辑缺陷:

可以利用 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); } }
|