Java动态代理与常规代理的有用性

我需要一些建议,对于动态代理在哪些情况下比常规代理更有用。

我花了很多精力来学习如何有效地使用动态代理。在这个问题上,撇开像AspectJ这样的框架基本上可以执行我们试图通过动态代理实现的所有事情,或者例如,CGLIB可以用来解决动态代理的一些缺点。

使用案例

  • 装饰器 - 例如,在方法调用时执行日志记录,或缓存复杂操作的返回值
  • 维护协定 - 即,确保参数在可接受的范围内,并且返回类型符合接受的值。
  • 适配器 - 在某处看到了一些聪明的文章,描述了这如何有用。不过,我很少遇到这种设计模式。

其他人是吗?

动态代理优势

  • 装饰器:记录所有方法调用,例如

public Object invoke(Object target, Method method, Object[] arguments) {
         System.out.println("before method " + method.getName());
         return method.invoke(obj, args);
     }
}

装饰器模式绝对有用,因为它允许对所有代理方法产生副作用(尽管此行为是使用方面的书籍示例..)。

  • Contract:与常规代理相比,我们不需要实现完整的接口。例如,

public Object invoke(Object target, Method method, Object[] arguments) {
     if ("getValues".equals(method.getName()) {
         // check or transform parameters and/or return types, e.g., 
         return RangeUtils.validateResponse( method.invoke(obj, args) );
     }

     if ("getVersion".equals(method.getName()) {
         // another example with no delegation
         return 3;
     }
} 

另一方面,合约只提供了避免实现完整接口的需要的好处。再说一次,重构代理方法会以静默方式使动态代理失效。

结论

所以我在这里看到的是一个真正的用例,一个可疑的用例。你怎么看?


答案 1

除了您描述的内容之外,动态代理还有许多潜在的用途 -

  1. 事件发布 - 在方法 x() 上,透明地调用 y() 或发送消息 z。
  2. 事务管理(用于数据库连接或其他事务性操作)
  3. 线程管理 - 透明地处理成本高昂的操作。
  4. 性能跟踪 - 例如,通过倒计时Latch检查的计时操作。
  5. 连接管理 - 考虑像Salesforce的企业API这样的API,它要求其服务的客户端在执行任何操作之前启动会话。
  6. 更改方法参数 - 如果您想传递 null 的默认值,如果这是您的此类事情。

除了验证和日志记录之外,这些只是几个选项,如您上面所述。FWIW,JSR 303,一个bean验证规范,在Hibernate Validator中有一个AOP样式的实现,所以你不需要专门为你的数据对象实现它。Spring框架还内置了验证功能,并且与AspectJ很好地集成了此处描述的一些内容。


答案 2

事实上,AOP使大多数动态代理受益。这是因为您可以围绕事先不知道的对象创建动态代理。

动态代理的另一个有用方面是当您要对所有方法应用相同的操作时。使用静态代理,您需要大量重复的代码(在每个代理方法上,您将需要对方法进行相同的调用,然后委托给代理对象),而动态代理将最大限度地减少这种情况。

另请注意,适配器和装饰器是单独的模式。它们在实现方式上看起来像代理模式(通过对象组合),但它们有不同的用途:

  • 装饰器模式允许您拥有多个混凝土装饰器,从而在运行时添加功能
  • 适配器模式旨在使对象适应不匹配的接口。我能想到的最好的例子是 - 它适应了界面。EnumetationIteratorEnumerationIterator

推荐