java动态代理与常规代理的实用性

java动态代理与常规代理的实用性,java,design-patterns,proxy,dynamic-proxy,use-case,Java,Design Patterns,Proxy,Dynamic Proxy,Use Case,我需要一些建议,在哪些情况下,动态代理比常规代理更有用 我花了很多精力学习如何有效地使用动态代理。在这个问题上,撇开像AspectJ这样的框架基本上可以执行我们试图通过动态代理实现的所有功能,或者例如CGLIB可以用来解决动态代理的一些缺点 用例 装饰器-例如,在方法调用上执行日志记录,或缓存复杂操作的返回值 维护合同-即确保参数在可接受的范围内,返回类型符合可接受的值 Adapter-在某个地方看到了一些聪明的文章,描述了这是如何有用的。但我很少遇到这种设计模式 其他人呢 动态代理优势

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

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

用例
  • 装饰器-例如,在方法调用上执行日志记录,或缓存复杂操作的返回值
  • 维护合同-即确保参数在可接受的范围内,返回类型符合可接受的值
  • Adapter-在某个地方看到了一些聪明的文章,描述了这是如何有用的。但我很少遇到这种设计模式
其他人呢

动态代理优势
  • Decorator:记录所有方法调用,例如

decorator模式非常有用,因为它允许对所有代理方法产生副作用(尽管此行为是使用方面的一个书籍示例)

  • 契约:与常规代理不同,我们不需要实现完整的接口。例如:

另一方面,合同只提供了避免实现完整接口的好处。同样,重构代理方法会使动态代理无效

结论
所以我在这里看到的是一个真实的用例和一个可疑的用例。您的看法是什么?

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

动态代理的另一个有用的方面是当您希望对所有方法应用相同的操作时。使用静态代理时,您需要大量重复的代码(在每个代理方法上,您需要对方法进行相同的调用,然后将其委托给代理对象),而动态代理会将此最小化

还要注意,适配器和装饰器是独立的模式。它们的实现方式(通过对象组合)类似于代理模式,但它们的用途不同:

  • decorator模式允许您拥有多个具体的decorator,从而在运行时添加功能
  • 适配器模式旨在使对象适应不匹配的接口。我能想到的最好的例子是
    枚举迭代器
    ——它将
    枚举
    调整为
    迭代器
    接口

动态代理有许多潜在用途,超出了您所描述的范围-

  • 事件发布-在方法x()上,透明地调用y()或发送消息z
  • 事务管理(用于数据库连接或其他事务性操作)
  • 线程管理—透明地执行昂贵的操作
  • 性能跟踪—例如,由倒计时锁存器检查的计时操作
  • 连接管理—考虑像Salesforce的企业API这样的API,这些API要求服务的客户端在执行任何操作之前启动会话
  • 更改方法参数-如果您想传递空值的默认值,如果您喜欢的话

  • 除了上面描述的验证和日志记录之外,这些只是一些选项。FWIW,JSR303,一个bean验证规范,在HibernateValidator中有一个AOP风格的实现,所以您不需要专门为您的数据对象实现它。Spring框架还内置了验证功能,并与AspectJ进行了很好的集成,实现了这里描述的一些功能。

    我能想到的另一个用例是在运行时动态实现接口,这是一些框架的工作方式


    例如,一个用于消费REST服务的Java库。您定义了一个反映RESTAPI中可用操作的Java接口,并用注释修饰方法以配置请求的细节。很容易看出,在这种情况下,接口中定义的所有方法都必须对某些服务器执行HTTP请求,将方法参数转换为请求参数;然后将响应解析为一个定义为方法返回类型的java对象。

    该死,我们需要java中的方法文本!我讨厌使用方法名的代码。事实上,当对所有方法应用相同的操作时,动态代理可能非常有用。我可以在验证或执行安全检查时看到这方面的用例。感谢您的全面列表,我可以肯定地看到有效的用例。你是对的,像hibernate和spring这样的框架提供了非常好的实现来解决其中一些问题,但是,在我可以直接证明使用动态代理的项目中,这两个框架都没有使用。除了第4点之外,其他原因在一般的系统模式设计方面都不是很好的实践。
    public Object invoke(Object target, Method method, Object[] arguments) {
             System.out.println("before method " + method.getName());
             return method.invoke(obj, args);
         }
    }
    
    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;
         }
    }