654 字
3 分钟
Dynamic Proxy in Java
虽然在一年前就知道了 Proxy 模式,但是基本没有尝试使用过,仅在框架里看到一些例子。昨天翻阅《大型网站系统与 Java 中间件实践》时,偶然发现了 Proxy 模式在 Java 中的应用 —— 动态代理,遂记录下来,顺便复习一下 Proxy 模式。
以下内容参考自
- 《 Design Patterns》
- 《大型网站系统与 Java 中间件实践》。
- http://www.baeldung.com/java-dynamic-proxies
Proxy 模式图示:

Proxy 模式
在《 Design Patterns》书中提到了使用 Proxy 模式的四种常见情况:
- 远程代理 (Remote Proxy) 为一个对象在不同的地址空间提供局部代表。
- 虚代理 (Virtual Proxy) 根据需要创建开销很大的对象。
- 保护代理 (Protection Proxy) 控制对原始对象的访问。保护代理用于对象应该有不同的访问权限的时候。
- 智能指针 (Smart Reference) 引用计数、实现线程安全、延迟创建,熟悉 C++ 的同学应该知道
std::share_ptr、std::weak_ptr、std::unique_ptr等。
Java 中的静态代理
这里借用 《大型网站系统与 Java 中间件实践》中的例子:
public interface Calculator { int add(int a, int b);}
public class CalculatorImpl implements Calculator { int add(int a, int b) { return a + b; }}
public class CalculatorProxy implements Calculator { private Calculator calculator;
public CalculatorProxy(Calculator calculator) { this.calculator = calculator; }
int add(int a, int b) { // We can do anything before and after real add is called, // such as logging return calculator.add(a, b); }}可以看到,在 CalculatorProxy 中我们可以调用了真正的 add 操作,并可以在 add 前后做很多额外的工作,这种方式看上去十分直接,但是如果我们有一批类需要代理,并且代理类中实现的功能是一致的,那么我们就需要为每一个类都实现一个 XxxProxy 类,这将会十分麻烦。
Java 中的动态代理
Java 中提供了一种方式使我们能够动态的生成一个类的代理,我们来看一个例子
public class DynamicProxyPlayground {
public static void main(String[] args) { Map mapProxyInstance = (Map) Proxy .newProxyInstance(DynamicProxyPlayground.class.getClassLoader(), new Class[]{Map.class}, new TimingDynamicInvocationHandler(new HashMap<String, String>()));
// DynamicProxyPlayground$TimingDynamicInvocationHandler invoke // INFO: Executing put finished in 74094 ns. mapProxyInstance.put("hello", "world");
CharSequence csProxyInstance = (CharSequence) Proxy.newProxyInstance( DynamicProxyPlayground.class.getClassLoader(), new Class[] { CharSequence.class }, new TimingDynamicInvocationHandler("Hello World"));
// DynamicProxyPlayground$TimingDynamicInvocationHandler invoke // INFO: Executing length finished in 11720 ns. csProxyInstance.length(); }
public static class TimingDynamicInvocationHandler implements InvocationHandler { private static Logger logger = Logger.getLogger(TimingDynamicInvocationHandler.class.getName());
private Object target;
private TimingDynamicInvocationHandler(Object target) { this.target = target; }
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { long start = System.nanoTime(); Object result = method.invoke(target, args); long elapsed = System.nanoTime() - start;
logger.info(String.format("Executing %s finished in %d ns.", method.getName(), elapsed)); return result; } }}在上述例子中,通过实现一个 InvocationHandler,我们就可以使用Proxy.newInstance为一批类创建功能相同的动态代理。
Dynamic Proxy in Java
https://blog.crazyark.xyz/zh/posts/dynamic_proxy/