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

发布于 2024-09-18 15:02:32 字数 1247 浏览 8 评论 0原文

我需要一些关于动态代理比常规代理更有用的场景的建议。

我投入了大量精力来学习如何有效地使用动态代理。在这个问题中,先不考虑像 AspectJ 这样的框架基本上可以执行我们尝试使用动态代理实现的所有功能,或者例如可以使用 CGLIB 来解决动态代理的一些缺点。

用例

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

其他人是吗?

动态代理的优点

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

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;
     }
} 

另一方面,契约仅带来避免实现完整接口的需要的好处。然而,重构代理方法会默默地使动态代理失效。

结论

所以我在这里看到的是一个真实的用例和一个有问题的用例。你有什么意见?

I need some advice to which scenarios a dynamic proxy would prove more useful than a regular proxy.

I've put alot of effort into learning how to use dynamic proxies effectively. In this question, set aside that frameworks like AspectJ can perform basically everything we try to achieve with dynamic proxies, or that e.g., CGLIB can be used to address some of the shortcomings of dynamic proxies.

Use cases

  • Decorators - e.g., perform logging on method invocation, or cache return values of complex operations
  • Uphold contract - That is, making sure parameters are within accepted range and return types conform to accepted values.
  • Adapter - Saw some clever article somewhere describing how this is useful. I rarely come across this design pattern though.

Are the others?

Dynamic proxy advantages

  • Decorator: Log all method invocations, e.g.,

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

The decorator pattern is definately useful as it allows side effects to all proxies methods (although this behaviour is a book-example of using aspects ..).

  • Contract: In contrast to a regular proxy, we need not implement the full interface. E.g.,

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;
     }
} 

The contract on the other hand only gives the benefit of avoiding the need to implement a complete interface. Then again, refactoring proxied methods would silently invalidate the dynamic proxy.

Conclusion

So what I see here is one real use case, and one questionable use case. What's your opinion?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

不及他 2024-09-25 15:02:32

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

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

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

There are a number of potential uses for dynamic proxies beyond what you've described -

  1. Event publishing - on method x(), transparently call y() or send message z.
  2. Transaction management (for db connections or other transactional ops)
  3. Thread management - thread out expensive operations transparently.
  4. Performance tracking - timing operations checked by a CountdownLatch, for example.
  5. Connection management - thinking of APIs like Salesforce's Enterprise API that require clients of their service to start a session before executing any operations.
  6. Changing method parameters - in case you want to pass default values for nulls, if that's your sort of thing.

Those are just a few options in addition to validation and logging like you've described above. FWIW, JSR 303, a bean validation specification, has an AOP-style implementation in Hibernate Validator, so you don't need to implement it for your data objects specifically. Spring framework also has validation built in and has really nice integration with AspectJ for some of the stuff described here.

小女人ら 2024-09-25 15:02:32

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

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

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

  • 装饰器模式允许您拥有多个具体装饰器,从而在运行时添加功能
  • 适配器模式旨在适应对象到一个不匹配的接口。我能想到的最好的例子是 EnumetationIterator - 它将 Enumeration 改编为 Iterator 接口。

Indeed AOP benefits most of the dynamic proxies. That's because you can create a dynamic proxy around an object that you don't know in advance.

Another useful side of a dynamic proxy is when you want to apply the same operation to all methods. With a static proxy you'd need a lot of duplicated code (on each proxied method you would need the same call to a method, and then delegate to the proxied object), and a dynamic proxy would minimize this.

Also note that Adapter and Decorator are separate patterns. They look like the Proxy pattern in the way they are implemented (by object composition), but they serve a different purpose:

  • the decorator pattern allows you to have multiple concrete decorators, thus adding functionality at runtime
  • the adapter pattern is meant to adapt an object to an unmatching interface. The best example I can think of is the EnumetationIterator - it adapts an Enumeration to the Iterator interface.
灯角 2024-09-25 15:02:32

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

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

Another use case I can think of is to dynamically implement interfaces at runtime, which is the way some frameworks work.

Take for instance Retrofit, a Java library for consuming REST services. You define a Java interface that reflects the operations available in the REST API, and decorate the methods with annotations to configure specifics of the request. It's easy to see that in this case all methods defined in the interface must execute a HTTP request against some server, transform the method arguments into request parameters; and then parse the response into a java object defined as the method return type.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文